//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
    THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 1995-1999  Microsoft Corporation

Module Name:

RilSimTKit.cpp

Abstract:


Notes:


--*/


/*
#------------------------------------------------------------------------------
#    Revision History
#    Date            Author           Activity ID         Activity Headline
#    2007-03-19    zuoxiaona         CEDB200047228       Submit STK CODE -RIL- lampson 
#    2007-03-27    zuoxiaona         CEDB200048982       Modify STK for Lampson 
#    2007-04-28    qinxuetao         WM600003778         Enable PPC to restore state after SIM reset
#    2007-06-22    qinxuetao         WM600007774         Modify STK input string encoding format, only UCS2 uses "HEX" format  
#------------------------------------------------------------------------------
*/

#include "precomp.h"
#undef assert
#include "Safeint.hxx"

typedef HRESULT (CRilSimToolkitCommand::*TLVPARSEFUNC)();

// A description of each toolkit command and which components it needs.  Note that the high bit is
// set if a component is optional, otherwise, it is mandatory
// NOTE: Open Channel is handled outside of this array of commands.
const g_rgdwTLV[] = {
      5, SIM_NOTIFY_DISPLAYTEXT, TEXTTAG, (ICONTAG | OPTIONALTAG), (IMMEDIATETAG | OPTIONALTAG),
      4, SIM_NOTIFY_GETINKEY, TEXTTAG, (ICONTAG | OPTIONALTAG),
      4, SIM_NOTIFY_SETUPIDLEMODETEXT, TEXTTAG, (ICONTAG | OPTIONALTAG),
      6, SIM_NOTIFY_GETINPUT, TEXTTAG, RESPONSETAG, (DEFTEXTTAG | OPTIONALTAG), (ICONTAG | OPTIONALTAG),
      2, SIM_NOTIFY_MORETIME,
      6, SIM_NOTIFY_PLAYTONE, (ALPHAIDTAG | OPTIONALTAG), (TONETAG | OPTIONALTAG), (DURATIONTAG | OPTIONALTAG), (ICONTAG | OPTIONALTAG),
      3, SIM_NOTIFY_POLLINTERVAL, DURATIONTAG,
      7, SIM_NOTIFY_SETUPMENU, ALPHAIDTAG, MENUITEMTAG, (NEXTACTIONTAG | OPTIONALTAG), (ICONTAG | OPTIONALTAG), (ICONLISTTAG | OPTIONALTAG),
      8, SIM_NOTIFY_SELECTITEM, (ALPHAIDTAG | OPTIONALTAG), MENUITEMTAG, (NEXTACTIONTAG | OPTIONALTAG), (ITEMIDTAG | OPTIONALTAG), (ICONTAG | OPTIONALTAG), (ICONLISTTAG | OPTIONALTAG),
      6, SIM_NOTIFY_SENDSMS, (ALPHAIDTAG | OPTIONALTAG), (ADDRESSTAG | OPTIONALTAG), TPDUTAG, (ICONTAG | OPTIONALTAG),
      5, SIM_NOTIFY_SENDSS, (ALPHAIDTAG | OPTIONALTAG), SSSTRINGTAG, (ICONTAG | OPTIONALTAG),
      5, SIM_NOTIFY_SENDUSSD, (ALPHAIDTAG | OPTIONALTAG), USSDSTRINGTAG, (ICONTAG | OPTIONALTAG),
      // Note: The SETUP CALL 2nd Alpha ID is handled as a special case in Parse Command.
      8, SIM_NOTIFY_SETUPCALL, (ALPHAIDTAG | OPTIONALTAG), ADDRESSTAG, (CAPABILITYTAG | OPTIONALTAG), (SUBADDRTAG | OPTIONALTAG), (DURATIONTAG | OPTIONALTAG), (ICONTAG | OPTIONALTAG),
      3, SIM_NOTIFY_REFRESH, (FILELISTTAG | OPTIONALTAG),   // Note -- this is optional or not depending on the fifth byte
      2, SIM_NOTIFY_POLLINGOFF,
      2, SIM_NOTIFY_LOCALINFO,
      3, SIM_NOTIFY_EVENTLIST, EVENTLISTTAG,
      9, SIM_NOTIFY_LAUNCHBROWSER, (BROWSERIDTAG | OPTIONALTAG), URLTAG, (BEARERTAG | OPTIONALTAG), (PROVISIONFILETAG | OPTIONALTAG), (TEXTTAG | OPTIONALTAG), (ALPHAIDTAG | OPTIONALTAG), (ICONTAG | OPTIONALTAG),
      4, SIM_NOTIFY_CLOSECHANNEL, (ALPHAIDTAG | OPTIONALTAG), (ICONTAG | OPTIONALTAG),
      5, SIM_NOTIFY_RECEIVEDATA, (ALPHAIDTAG | OPTIONALTAG),  (ICONTAG | OPTIONALTAG), CHANNELDATALENTAG,
      5, SIM_NOTIFY_SENDDATA, (ALPHAIDTAG | OPTIONALTAG),  (ICONTAG | OPTIONALTAG), CHANNELDATATAG,
      5, SIM_NOTIFY_SENDDTMF, (ALPHAIDTAG | OPTIONALTAG), DTMFTAG, (ICONTAG | OPTIONALTAG),
      3, SIM_NOTIFY_LANGUAGENOTIFICATION, (LANGUAGETAG | OPTIONALTAG),
      4, SIM_NOTIFY_RUNATCOMMAND, ATCMDTAG, (ICONTAG | OPTIONALTAG),
      0
};

/****************************************************************************

    FUNCTION:   CRilSimToolkitCommand

    PURPOSE:    CRilSimToolkitCommand class constructor

    PARAMETERS: None

    RETURNS:    HRESULT

****************************************************************************/

CRilSimToolkitCommand::CRilSimToolkitCommand()
: m_fTextNotifications(FALSE)
{
    FUNCTION_TRACE(CRilSimToolkitCommand::CRilSimToolkitCommand);

#if defined(OEM2_SIMTOOLKIT)||defined(WAVECOM_DRIVER)   
    m_fTextNotifications = TRUE;
#else
    m_fTextNotifications = FALSE;
#endif //defined(OEM2_SIMTOOLKIT)
}


/****************************************************************************

    FUNCTION:   ~CRilSimToolkitCommand

    PURPOSE:    CRilSimToolkitCommand class destructor

    PARAMETERS: None

    RETURNS:    HRESULT

****************************************************************************/

CRilSimToolkitCommand::~CRilSimToolkitCommand()
{
    FUNCTION_TRACE(CRilSimToolkitCommand::~CRilSimToolkitCommand);
}


/****************************************************************************

    FUNCTION:   ParseCommand

    PURPOSE:    Parses a Proactive SIM command, returning a structure
                containing the command details suitable for passing
                to SIMTKit.

    PARAMETERS: szData - Data from SIM card
                dwDataSize - Size of that data
                ppCommand - Resulting structure to send to caller
                pdwCommandId - ID of this command
                pdwNotifyCode - What the notification code is

    RETURNS:    DWORD - SIMTKit response code.

****************************************************************************/

DWORD CRilSimToolkitCommand::ParseCommand(LPCSTR szData, DWORD dwDataSize, RILSIMTOOLKITCMD **ppCommand, DWORD *pdwCommandSize)
{
    FUNCTION_TRACE(CRilSimToolkitCommand::ParseCommand);

    HRESULT hr;
    DWORD dwRetVal = SIM_RESPONSE_OK;
    DWORD dwResultSize = 0;
    DWORD dwNotifyCode = 0;
    DWORD dwCommandId = 0;
    DWORD dwCommandTag = 0;
    DWORD i;
    DWORD numTLVs;
    DWORD dwTag;
    BYTE bFifthByte = 0;
    LPBYTE lpbResult = NULL;
    DWORD *pdwTLV;
    RILSIMTOOLKITCMD* pCmd = NULL;
    const TLVPARSEFUNC rglpfnParse[] = { NULL, NULL, NULL, NULL, ReadDuration,                  // 0x00 - 0x04
            ReadAlphaIdentifier, ReadAddress, ReadCapability, ReadSubAddress, ReadShortString,  // 0x05 - 0x09
            ReadUSSD, ReadTPDU, NULL, ReadTextString, ReadTone,                                 // 0x0A - 0x0E
            ReadMenuItem, ReadItemIdentifier, ReadResponseLength, ReadFileList, NULL,           // 0x0F - 0x13
            NULL, NULL, NULL, ReadDefaultTextString, ReadNextAction,                            // 0x14 - 0x18
            ReadEventList, NULL, NULL, NULL, NULL,                                              // 0x19 - 0x1D
            ReadIconIdentifier, ReadIconIdentifierList, NULL, NULL, NULL,                       // 0x1E - 0x22
            NULL, NULL, NULL, NULL, NULL,                                                       // 0x23 - 0x27
            ReadATCommand, NULL, NULL, ReadImmediate, ReadDTMF,                                 // 0x28 - 0x2C
            ReadLanguage, NULL, NULL, ReadBrowserIdentity, ReadURL,                             // 0x2D - 0x31
            ReadBearer, ReadProvisionFileList, NULL, NULL, ReadChannelData,                     // 0x32 - 0x36
            ReadChannelDataLength                                                               // 0x37
            };


    // Assert parameters
    DEBUGCHK(*ppCommand == NULL);
    DEBUGCHK(szData != NULL);

    // Check parameters
    if (szData == NULL)
    {
        dwRetVal = SIM_RESPONSE_ERR_MOBILEINCAPABLE;
        goto Exit;
    }

    // Set up some variables
    m_lpbParse = NULL;
    m_dwParseLen = 0;
    m_pwszAlphaId = NULL;
    m_pwszText = NULL;
    m_pwszDefaultText = NULL;
    m_pwszAddress = NULL;
    m_pwszSubAddr = NULL;
    m_pwszUSSD = NULL;
    m_lpbTPDU = NULL;
    m_dwAlphaIdLen = 0;
    m_dwTextLen = 0;
    m_dwDefaultTextLen = 0;
    m_dwAddressLen = 0;
    m_dwSubAddrLen = 0;
    m_dwUSSDLen = 0;
    m_dwTPDULen = 0;
    m_dwNumFiles = 0;
    m_dwDuration = SIMTONE_DEFAULTDURATION;
    m_dwDuration2 = SIMOPENCHANNEL_DEFAULTDURATION;
    m_dwTone = SIMTONE_DEFAULT;
    m_dwMinResponse = 1;
    m_dwMaxResponse = 1;
    m_dwItemId = 0xffffffff;
    m_rgpsmi = NULL;
    m_numpsmi = 0;
    m_dwAddrType = SIM_ADDRTYPE_UNKNOWN;
    m_dwNumPlan = SIM_NUMPLAN_UNKNOWN;
    m_pdwFiles = NULL;
    m_lpbEventList = NULL;
    m_dwEventListLen = 0;
    m_dwBrowserId = 0xffffffff;
    m_pwszURL = NULL;
    m_dwURLLen = 0;
    m_lpbBearer = NULL;
    m_dwBearerLen = 0;
    m_rgpsfr = NULL;
    m_numpsfr = 0;
    m_pwszDTMF = NULL;
    m_dwDTMFLen = 0;
    m_lpbChannelData = NULL;
    m_dwChannelDataLen = 0;
    m_dwChannelDataLength = 0xffffffff;
    m_dwDeviceSrcId = 0;
    m_dwDeviceDestId = 0;
    m_pwszLanguage = NULL;
    m_dwLanguageLen = 0;
    m_dwLocalAddrType = 0;
    m_lpbLocalAddr = NULL;
    m_dwLocalAddrLen = 0;
    m_lpbDestAddr = NULL;
    m_dwDestAddrLen = 0;
    m_pwszLogin = NULL;
    m_dwLoginLen = 0;
    m_pwszPassword = NULL;
    m_dwPasswordLen = 0;
    m_dwDestAddrType = 0;
    m_dwBearerDescType = 0;
    m_lpbBearerDesc = NULL;
    m_dwBearerDescLen = 0;
    m_dwBufferSize = 0;
    m_dwProtocolType = 0;
    m_dwPortNum = 0;
    m_lpbAccessName = NULL;
    m_dwAccessNameLen = 0;
    m_fImmediateResponse = FALSE;
    m_dwIconIdentifier = SIMTKIT_INVALID_VALUE;
    m_dwIconQualifier = SIMTKIT_INVALID_VALUE;
    m_pwszAlphaId2 = NULL;
    m_dwAlphaId2Len = 0;
    m_dwIconIdentifier2 = SIMTKIT_INVALID_VALUE;
    m_dwIconQualifier2 = SIMTKIT_INVALID_VALUE;

    // Text based, comma delimited commands passed from the radio.
    if (m_fTextNotifications)
    {
        m_lpbParse = (LPBYTE)szData;
        m_dwParseLen = dwDataSize;
#if defined(WAVECOM_DRIVER)
        hr = ParseDFTextFormatCommand(&dwNotifyCode, &bFifthByte, &dwRetVal);     
#else
        hr = ParseTextFormatCommand(&dwNotifyCode, &bFifthByte, &dwRetVal);
#endif

        if (FAILED(hr))
        {
            DEBUGCHK(FALSE);
            RETAILMSG(MSG_ON, (TEXT("RILDrv : SIMTKit: Parsing of command %x failed.\r\n"), dwNotifyCode));
            dwRetVal = SIM_RESPONSE_ERR_MOBILEINCAPABLE;
            goto Exit;
        }
    }
    // Byte based commands from the radio.
    else
    {
        m_lpbParse = (LPBYTE)szData;

        // First comes the proactive SIM command tag
        if (*(m_lpbParse++) != 0xD0)
        {
            // Unexpected command
            RETAILMSG(MSG_ON, (TEXT("RILDrv : SIMTKit: First byte is %x, expected 0xD0\r\n"), *(m_lpbParse - 1)));
            dwRetVal = SIM_RESPONSE_ERR_COMMANDNUMBER;
            goto Exit;
        }

        // Then comes the length -- note we have to be a little sly here -- this actually ends up
        // changing m_dwParseLen, but what I really want to do is SET m_dwParseLen here
        m_dwParseLen = 5;
        if ( dwDataSize < m_dwParseLen )
        {
            m_dwParseLen = 0;
        }
        hr = ReadCmdLength(&m_dwParseLen);
        if (FAILED(hr))
        {
            RETAILMSG(MSG_ON, (TEXT("RILDrv : SIMTKit: ReadCmdLength returned error\r\n")));
            dwRetVal = SIM_RESPONSE_ERR_COMMANDNUMBER;
            goto Exit;
        }

        ASSERT(m_dwParseLen == (dwDataSize - 2) || m_dwParseLen == (dwDataSize - 3));
        if (m_dwParseLen < 9)
        {
            // Invalid -- even MORETIME has 9 bytes more
            RETAILMSG(MSG_ON, (TEXT("RILDrv : SIMTKit: Not enough bytes for command details, expected at least 9, saw %d\r\n"), m_dwParseLen));
            dwRetVal = SIM_RESPONSE_ERR_COMMANDNUMBER;
            goto Exit;
        }

        // First byte -- the command details tag. Save this because a proper terminal response requires
        // the command details to be identical to the proactive commands, including comprehension settings.
        dwCommandTag = (DWORD) (*(m_lpbParse++));

        if ((dwCommandTag & 0x7f) != COMMANDIDTAG)
        {
            // Invalid
            RETAILMSG(MSG_ON, (TEXT("RILDrv : SIMTKit: Expected Command ID Tag, saw %x\r\n"), dwCommandTag));
            dwRetVal = SIM_RESPONSE_ERR_COMMANDNUMBER;
            goto Exit;
        }

        // Second byte -- length, should be 3
        if (*(m_lpbParse++) != 3)
        {
            RETAILMSG(MSG_ON, (TEXT("RILDrv : SIMTKit: Expected 3 in second byte of Command ID, saw %x\r\n"), *(m_lpbParse - 1)));
            dwRetVal = SIM_RESPONSE_ERR_COMMANDNUMBER;
            goto Exit;
        }

        // Third byte -- the command number
        dwCommandId = (DWORD) (*(m_lpbParse++));

        // Fourth byte -- the command (fifth byte is command-specific data)
        dwNotifyCode = (DWORD) (*(m_lpbParse++));
        bFifthByte = *(m_lpbParse++);
        RETAILMSG(MSG_ON, (TEXT("RILDrv : SIMTKit: Command ID %x, Notification %x, Fifth Byte %x\r\n"), dwCommandId, dwNotifyCode, bFifthByte));

        // The next 4 bytes are "device identities" -- we ignore these,
        // but the first byte should be 2 and so should the second byte
        if ((*(m_lpbParse++) & 0x7f) != DEVICEIDTAG)
        {
            // Invalid
            RETAILMSG(MSG_ON, (TEXT("RILDrv : SIMTKit: Expected Device ID Tag, saw %x\r\n"), *(m_lpbParse - 1)));
            dwRetVal = SIM_RESPONSE_ERR_COMMANDDATA;
            goto Exit;
        }

        // Next byte -- length, should be 2
        if (*(m_lpbParse++) != 2)
        {
            RETAILMSG(MSG_ON, (TEXT("RILDrv : SIMTKit: Expected Device ID Length of 2, saw %x\r\n"), *(m_lpbParse - 1)));
            dwRetVal = SIM_RESPONSE_ERR_COMMANDDATA;
            goto Exit;
        }

        // Source and destination device ID's.
        m_dwDeviceSrcId = (DWORD) (*(m_lpbParse++));
        m_dwDeviceDestId = (DWORD) (*(m_lpbParse++));
        m_dwParseLen -= 9;


        // Special parsing for Open channel commands
        if (SIM_NOTIFY_OPENCHANNEL == dwNotifyCode)
        {
            // Parse Optional alphaID
            if ((m_dwParseLen > 0) && ((*m_lpbParse & 0x7f) == (BYTE)ALPHAIDTAG))
            {
                m_lpbParse++;
                m_dwParseLen--;
                hr = ReadAlphaIdentifier();
                if (FAILED(hr))
                {
                    // Failure
                    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: Function for TLV AlphaID failed while parsing Open Channel.\r\n")));
                    dwRetVal = SIM_RESPONSE_ERR_VALUESMISSING;
                    goto Exit;
                }
            }

            // Parse optional Icon Identifier
            if ((m_dwParseLen > 0) && ((*m_lpbParse & 0x7f) == (BYTE)ICONTAG))
            {
                m_lpbParse++;
                m_dwParseLen--;
                hr = ReadIconIdentifier();
                if (FAILED(hr))
                {
                    // Failure
                   RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: Function for TLV IconID failed while parsing Open Channel.\r\n")));
                    dwRetVal = SIM_RESPONSE_ERR_VALUESMISSING;
                    goto Exit;
                }
            }

            // The next TLV tag will determine how the rest of the Open Channel command is parsed.
            switch ((*(m_lpbParse) & 0x7f))
            {
                case SIMTK_OPENCHANNEL_CS:
                    hr = ByteParseOpenChannelCS(&dwRetVal);
                    break;
                case SIMTK_OPENCHANNEL_GPRS:
                    hr = ByteParseOpenChannelGPRS(&dwRetVal);
                    break;
                default:
                    // We don't know this Open Channel command, so we have to fail
                    RETAILMSG(MSG_ON, (TEXT("RILDrv : SIMTKit: SimToolkit Open Channel parsing encountered unknown firs tag 0x%x\r\n"), *m_lpbParse));
                    dwRetVal = SIM_RESPONSE_ERR_COMMANDTYPE;
                    goto Exit;
            }

            if (FAILED(hr))
            {
                dwRetVal = SIM_RESPONSE_ERR_VALUESMISSING;
                goto Exit;
            }
        }
        else
        {
            // Now we're ready for some TLVs -- which TLVs we need depends on which code we have, so let's
            // go through our array to see which TLVs we are interested in
            pdwTLV = (DWORD *) g_rgdwTLV;

            while (*pdwTLV && (pdwTLV[1] != dwNotifyCode))
            {
                // Skip to the next command
                pdwTLV += (*pdwTLV);
            }

            if (!(*pdwTLV))
            {
                // We don't know this command, so we have to fail
                RETAILMSG(MSG_ON, (TEXT("RILDrv : SIMTKit: SimToolkit encountered unknown command %x\r\n"), dwNotifyCode));
                dwRetVal = SIM_RESPONSE_ERR_COMMANDTYPE;
                goto Exit;
            }

            // OK, let's go through now and see if we have each of the needed TLVs
            numTLVs = *pdwTLV - 2;
            pdwTLV += 2;
            for (i = 0; i < numTLVs; i++)
            {
                dwTag = (pdwTLV[i] & ~OPTIONALTAG);

                // Only pay attention to the lower 7 bits...
                if ((m_dwParseLen == 0) || ((*m_lpbParse & 0x7f) != (BYTE) dwTag))
                {
                    // Nope, this isn't this tag -- this is OK, so long as this is optional,
                    // otherwise, we have a failure on our hands
                    if (!(pdwTLV[i] & OPTIONALTAG))
                    {
                        RETAILMSG(MSG_ON, (TEXT("RILDrv : SIMTKit: Mandatory TLV %x not found\r\n"), dwTag));
                        dwRetVal = SIM_RESPONSE_ERR_COMMANDDATA;
                        goto Exit;
                    }
                }
                else if (m_dwParseLen > 0)
                {
                    // Great, let's process this one.  Good thing we have an array which tells us
                    // which function to call, that's very useful
                    RETAILMSG(MSG_ON, (TEXT("RILDrv : SIMTKit: Processing tag %x\r\n"), dwTag));

                    m_lpbParse++;
                    m_dwParseLen--;
                    hr = (this->*rglpfnParse[dwTag])();
                    if (FAILED(hr))
                    {
                        // Failure
                        RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: Function for TLV %x failed\r\n"), (pdwTLV[i] & ~OPTIONALTAG)));
                        dwRetVal = SIM_RESPONSE_ERR_VALUESMISSING;
                        goto Exit;
                    }
                }
            }

            // Special handling for SETUP CALL's 2nd alpha ID and icon.
            if ((SIM_NOTIFY_SETUPCALL == dwNotifyCode) && (0 < m_dwParseLen))
            {
                if ((*m_lpbParse & 0x7f) == (BYTE)ALPHAIDTAG)
                {
                    m_lpbParse++;
                    m_dwParseLen--;
                    hr = ReadCommonEFADNText(&m_pwszAlphaId2, &m_dwAlphaId2Len);
                    if (FAILED(hr))
                    {
                        // Failure
                        RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: Parsing SETUP CALL 2nd Alpha ID failed.\r\n")));
                        dwRetVal = SIM_RESPONSE_ERR_VALUESMISSING;
                        goto Exit;
                    }
                }

                if ( (0 < m_dwParseLen) &&
                     ( (*m_lpbParse & 0x7f) == (BYTE)ICONTAG) )
                {
                    m_lpbParse++;
                    m_dwParseLen--;
                    hr = ReadCommonIconIdentifier(&m_dwIconIdentifier2, &m_dwIconQualifier2);
                    if (FAILED(hr))
                    {
                        // Failure
                        RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: Parsing SETUP CALL 2nd Icon failed.\r\n")));
                        dwRetVal = SIM_RESPONSE_ERR_VALUESMISSING;
                        goto Exit;
                    }
                }
            }
        }
    }

    // Finally, we can put everything back together into a structure
    switch (dwNotifyCode)
    {
        case SIM_NOTIFY_MORETIME:
        case SIM_NOTIFY_POLLINGOFF:
            // Fifth byte is unused -- nothing really more to do, is there?
            dwResultSize = 0;
            break;

        // These all use the SIMTEXT structure
        case SIM_NOTIFY_DISPLAYTEXT:
        case SIM_NOTIFY_GETINKEY:
        case SIM_NOTIFY_GETINPUT:
        case SIM_NOTIFY_SETUPIDLEMODETEXT:
            hr = BuildSIMTEXT(dwNotifyCode, bFifthByte, &lpbResult, &dwResultSize);
            break;

        // These both use the SIMMENU structure
        case SIM_NOTIFY_SETUPMENU:
        case SIM_NOTIFY_SELECTITEM:
            hr = BuildSIMMENU(dwNotifyCode, bFifthByte, &lpbResult, &dwResultSize);
            break;

        case SIM_NOTIFY_POLLINTERVAL:
            hr = BuildSIMPOLLINGINTERVAL(dwNotifyCode, bFifthByte, &lpbResult, &dwResultSize);
            break;

        case SIM_NOTIFY_SETUPCALL:
            hr = BuildSIMCALL(dwNotifyCode, bFifthByte, &lpbResult, &dwResultSize);
            break;

        case SIM_NOTIFY_PLAYTONE:
            hr = BuildSIMTONE(dwNotifyCode, bFifthByte, &lpbResult, &dwResultSize);
            break;

        case SIM_NOTIFY_LOCALINFO:
            hr = BuildSIMLOCALINFO(dwNotifyCode, bFifthByte, &lpbResult, &dwResultSize);
            break;

        case SIM_NOTIFY_REFRESH:
            hr = BuildSIMREFRESH(dwNotifyCode, bFifthByte, &lpbResult, &dwResultSize);
            if (E_FAIL == hr)
            {
                // A reserved refresh mode was sent, a "command type not understood" response
                // must be sent back.
                RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: Reserved REFRESH command mode. Sending command type not understood.\r\n")));
                DEBUGCHK(FALSE);
                dwRetVal = SIM_RESPONSE_ERR_COMMANDTYPE;
                goto Exit;
            }
            else if (E_INVALIDARG == hr)
            {
                // A refresh mode requiring a file list was sent but no file list was attached, a
                //"error, required values missing" response will be sent back.
                RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: REFRESH command mode requiring file list sent with a file list. Responding with error values missing.\r\n")));
                DEBUGCHK(FALSE);
                dwRetVal = SIM_RESPONSE_ERR_VALUESMISSING;
                goto Exit;
            }

            // SIM_RESPONSE_ERR_VALUESMISSING
            break;

        case SIM_NOTIFY_SENDSS:
        case SIM_NOTIFY_SENDUSSD:
            hr = BuildSIMUSSD(dwNotifyCode, bFifthByte, &lpbResult, &dwResultSize);
            break;

        case SIM_NOTIFY_SENDSMS:
            hr = BuildSIMSMS(dwNotifyCode, bFifthByte, &lpbResult, &dwResultSize);
            break;

        case SIM_NOTIFY_EVENTLIST:
            hr = BuildSIMEVENTLIST(dwNotifyCode, bFifthByte, &lpbResult, &dwResultSize);
            break;

        case SIM_NOTIFY_LAUNCHBROWSER:
            hr = BuildSIMLAUNCHBROWSER(dwNotifyCode, bFifthByte, &lpbResult, &dwResultSize);
            break;

        case SIM_NOTIFY_SENDDTMF:
            hr = BuildSIMSENDDTMF(dwNotifyCode, bFifthByte, &lpbResult, &dwResultSize);
            break;

        case SIM_NOTIFY_OPENCHANNEL:
            hr = BuildSIMOPENCHANNEL(dwNotifyCode, bFifthByte, &lpbResult, &dwResultSize);
            break;

        case SIM_NOTIFY_CLOSECHANNEL:
            hr = BuildSIMCLOSECHANNEL(dwNotifyCode, bFifthByte, &lpbResult, &dwResultSize);
            break;

        case SIM_NOTIFY_SENDDATA:
            hr = BuildSIMSENDDATA(dwNotifyCode, bFifthByte, &lpbResult, &dwResultSize);
            break;

        case SIM_NOTIFY_RECEIVEDATA:
            hr = BuildSIMRECEIVEDATA(dwNotifyCode, bFifthByte, &lpbResult, &dwResultSize);
            break;

        case SIM_NOTIFY_LANGUAGENOTIFICATION:
            hr = BuildSIMLANGUAGE(dwNotifyCode, bFifthByte, &lpbResult, &dwResultSize);
            break;

        case SIM_NOTIFY_RUNATCOMMAND:
            hr = BuildSIMRUNATCMD(dwNotifyCode, bFifthByte, &lpbResult, &dwResultSize);
            break;

        default:
            // We don't understand this command
            RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: Don't understand command %x\r\n"), dwNotifyCode));
            ASSERT(0);
            dwRetVal = SIM_RESPONSE_ERR_COMMANDTYPE;
            goto Exit;
    }

    if (FAILED(hr))
    {
        // Oh, we couldn't build the information -- since we were able to parse everything
        // out OK, we have to assume this is an internal error
        ASSERT(hr == E_OUTOFMEMORY);
        dwRetVal = SIM_RESPONSE_ERR_MOBILEINCAPABLE;
    }

    // Everything was parsed ok. Build up the final structure to be sent with the
    // SIM toolkit notification.
    if (SIM_RESPONSE_OK == dwRetVal)
    {
        // Build RIL SIMTKit command structure.
        // Total size will be the command size plus the details.
        *pdwCommandSize = ROUNDTODWORD(sizeof(RILSIMTOOLKITCMD) + dwResultSize);
        pCmd = (RILSIMTOOLKITCMD*)AllocBlob(*pdwCommandSize);

        if (NULL == pCmd)
        {
            ASSERT(FALSE);
            *pdwCommandSize = 0;
            dwRetVal = SIM_RESPONSE_ERR_MOBILEINCAPABLE;
            goto Exit;
        }

        memset(pCmd, 0, *pdwCommandSize);
        pCmd->cbSize = *pdwCommandSize;

        if (m_fTextNotifications)
        {
            pCmd->dwType = dwNotifyCode;
            pCmd->dwParams = RIL_PARAM_SIMTKIT_CMD_TYPE;
        }
        else
        {
            pCmd->dwId = dwCommandId;
            pCmd->dwTag = dwCommandTag;
            pCmd->dwType = dwNotifyCode;
            pCmd->dwQualifier = bFifthByte;
            pCmd->dwParams = RIL_PARAM_SIMTKIT_CMD_ID | RIL_PARAM_SIMTKIT_CMD_TAG | RIL_PARAM_SIMTKIT_CMD_TYPE | RIL_PARAM_SIMTKIT_CMD_QUALIFIER;
        }

        if (NULL != lpbResult)
        {
            pCmd->dwParams |= RIL_PARAM_SIMTKIT_CMD_DETAILS_SIZE | RIL_PARAM_SIMTKIT_CMD_DETAILS_OFFSET;
            pCmd->dwDetailsSize = dwResultSize;
            pCmd->dwDetailsOffset = ROUNDTODWORD(sizeof(RILSIMTOOLKITCMD));

            memcpy((LPBYTE*)((LPBYTE)pCmd + pCmd->dwDetailsOffset), lpbResult, dwResultSize);
            delete[] lpbResult;
            lpbResult = NULL;
        }
    }

Exit:
    // Error with parsing the SIM toolkit notification.
    if (dwRetVal != SIM_RESPONSE_OK)
    {
        // Free up any previously allocated memory
        delete[] lpbResult;
        lpbResult = NULL;
        if (NULL != pCmd)
        {
            FreeBlob(pCmd);
            pCmd = NULL;
        }

        // Now try creating an error notification, if possible, to inform the upper layers
        // of the SIM toolkit parsing failure.
        *pdwCommandSize = ROUNDTODWORD(sizeof(RILSIMTOOLKITCMD));
        pCmd = (RILSIMTOOLKITCMD*)AllocBlob(*pdwCommandSize);

        // Out of memory problem, just exit.
        if (NULL == pCmd)
        {
            ASSERT(FALSE);
            *pdwCommandSize = 0;
            dwRetVal = SIM_RESPONSE_ERR_MOBILEINCAPABLE;
        }
        else
        {
            memset(pCmd, 0, *pdwCommandSize);
            pCmd->cbSize = *pdwCommandSize;

            // Set the command ID, if available.
            if (0 != dwCommandId)
            {
                pCmd->dwId = dwCommandId;
                pCmd->dwParams |= RIL_PARAM_SIMTKIT_CMD_ID;
            }

            // Set the command ID, if available.
            if (0 != dwCommandTag)
            {
                pCmd->dwTag = dwCommandTag;
                pCmd->dwParams |= RIL_PARAM_SIMTKIT_CMD_TAG;
            }

            // Set the command type, if available.
            if (0 != dwNotifyCode)
            {
                pCmd->dwType = dwNotifyCode;
                pCmd->dwParams |= RIL_PARAM_SIMTKIT_CMD_TYPE;
            }

            // Set the command type, if available.
            if (0 != bFifthByte)
            {
                pCmd->dwQualifier = bFifthByte;
                pCmd->dwParams |= RIL_PARAM_SIMTKIT_CMD_QUALIFIER;
            }

            // Set the error value.
            pCmd->dwError = dwRetVal;
            pCmd->dwParams |= RIL_PARAM_SIMTKIT_CMD_ERROR;
        }
    } // dwRetVal != SIM_RESPONSE_OK

    *ppCommand = pCmd;

    // In any case, we definitely want to free m_rgpsmi if it was allocated
    if (NULL != m_rgpsmi)
    {
        for (i = 0; i < m_numpsmi; i++)
        {
            delete[] (BYTE*)m_rgpsmi[i];
        }
        delete[] m_rgpsmi;
    }

    if (NULL != m_rgpsfr)
    {
        for (i = 0; i < m_numpsfr; i++)
        {
            delete[] (BYTE*)m_rgpsfr[i];
        }
        delete[] m_rgpsfr;
    }

    delete[] m_pwszAlphaId;
    delete[] m_pwszAlphaId2;
    delete[] m_pwszText;
    delete[] m_pwszDefaultText;
    delete[] m_pwszAddress;
    delete[] m_pwszSubAddr;
    delete[] m_pwszUSSD;
    delete[] m_lpbTPDU;
    delete[] m_lpbEventList;
    delete[] m_pdwFiles;
    delete[] m_pwszURL;
    delete[] m_lpbBearer;
    delete[] m_pwszDTMF;
    delete[] m_lpbChannelData;
    delete[] m_pwszLanguage;
    delete[] m_lpbLocalAddr;
    delete[] m_lpbDestAddr;
    delete[] m_pwszLogin;
    delete[] m_pwszPassword;
    delete[] m_lpbBearerDesc;
    delete[] m_lpbAccessName;

    return dwRetVal;
}

/****************************************************************************

    FUNCTION:   BuildSIMMENU

    PURPOSE:    Builds the SIMMENU structure

    PARAMETERS: dwNotifyCode - Which command is this?
                bFifthByte - The fifth byte from the command details
                ppbResult - OUT parameter to hold allocated structure

    RETURNS:    HRESULT

****************************************************************************/

HRESULT CRilSimToolkitCommand::BuildSIMMENU(DWORD dwNotifyCode, BYTE bFifthByte, LPBYTE *ppbResult, DWORD *lpdwSize)
{
    SIMMENU *psm = NULL;
    SIMMENUITEM *psmi;
    HRESULT hr = S_OK;
    DWORD dwSize, i;
    unsigned int uiSize;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMMENU\r\n")));

    dwNotifyCode;  // Avoid warning C4100: unreferenced formal parameter

    // How much space do we need to allocate?
    BOOL fSafeDword = FALSE;
    if ( TRUE == safeIntUAdd( ROUNDTODWORD(sizeof(SIMMENU)), ROUNDTODWORD(m_dwAlphaIdLen), &uiSize ))
    {
        for (i = 0, fSafeDword = TRUE; (i < m_numpsmi) && (TRUE == fSafeDword); i++)
        {
            fSafeDword = safeIntUAdd(uiSize, ROUNDTODWORD(m_rgpsmi[i]->cbSize), &uiSize);
        }
    }
    if ( FALSE == fSafeDword )
    {
        hr = E_ABORT;
        goto Exit;
    }
    else
    {
        dwSize = uiSize;
    }

    if ( dwSize == 0 )
    {
        hr = E_ABORT;
        goto Exit;
    }


    psm = (SIMMENU *) new BYTE[dwSize];
    if (!psm)
    {
        hr = E_OUTOFMEMORY;
        goto Exit;
    }

    // Populate this structure
    memset(psm, 0, dwSize);
    psm->cbSize = dwSize;
    psm->dwParams = SIM_PARAM_SIMMENU_FLAGS | SIM_PARAM_SIMMENU_MENUITEMCOUNT |
                    SIM_PARAM_SIMMENU_MENUITEMSIZE | SIM_PARAM_SIMMENU_MENUITEMOFFSET;
    psm->dwFlags = (bFifthByte & 0x80) ? SIMMENU_HELPINFO : 0;
    if (m_dwAlphaIdLen)
    {
        psm->dwParams |= (SIM_PARAM_SIMMENU_TEXTSIZE | SIM_PARAM_SIMMENU_TEXTOFFSET);
        psm->dwTextSize = m_dwAlphaIdLen;
        psm->dwTextOffset = ROUNDTODWORD(sizeof(SIMMENU));
        lstrcpy(((TCHAR *) ((LPBYTE) psm + psm->dwTextOffset)), m_pwszAlphaId);
    }
    if (m_dwItemId != -1)
    {
        psm->dwParams |= SIM_PARAM_SIMMENU_DEFAULTITEM;
        psm->dwDefaultItem = m_dwItemId;
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconIdentifier)
    {
        psm->dwParams |= SIM_PARAM_SIMMENU_ICONID;
        psm->dwIconIdentifier = m_dwIconIdentifier;
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconQualifier)
    {
        psm->dwParams |= SIM_PARAM_SIMMENU_ICONQUALIFIER;
        psm->dwIconQualifier = m_dwIconQualifier;
    }

    // Now for the menu items
    psm->dwMenuItemCount = m_numpsmi;
    psm->dwMenuItemOffset = (m_dwAlphaIdLen) ? (psm->dwTextOffset + ROUNDTODWORD(psm->dwTextSize))
                                        : ROUNDTODWORD(sizeof(SIMMENU));
    psm->dwMenuItemSize = dwSize - psm->dwMenuItemOffset;

    psmi = (SIMMENUITEM *) ((LPBYTE) psm + psm->dwMenuItemOffset);
    for (i = 0; i < m_numpsmi; i++)
    {
        DWORD cbSize = m_rgpsmi[i]->cbSize;

        memcpy(psmi, m_rgpsmi[i], cbSize);
        psmi = (SIMMENUITEM *) ((LPBYTE) psmi + cbSize);
    }

    *lpdwSize = dwSize;

Exit:
    *ppbResult = (LPBYTE) psm;
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::BuildSIMMENU\r\n")));
    return hr;
}

/****************************************************************************

    FUNCTION:   BuildSIMTEXT

    PURPOSE:    Builds the SIMTEXT structure

    PARAMETERS: dwNotifyCode - Which command is this?
                bFifthByte - The fifth byte from the command details
                ppbResult - OUT parameter to hold allocated structure

    RETURNS:    HRESULT

****************************************************************************/

HRESULT CRilSimToolkitCommand::BuildSIMTEXT(DWORD dwNotifyCode, BYTE bFifthByte, LPBYTE *ppbResult, DWORD *lpdwSize)
{
    SIMTEXT *pst = NULL;
    HRESULT hr = S_OK;
    DWORD dwSize;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMTEXT\r\n")));

    // OK, now let's pack this all into a SIMTEXT structure -- in this case, there is
    // no default text, so we don't have to worry about that
    dwSize = ROUNDTODWORD(sizeof(SIMTEXT)) + ROUNDTODWORD(m_dwTextLen) + ROUNDTODWORD(m_dwDefaultTextLen);
    pst = (SIMTEXT *) new BYTE[dwSize];
    if (!pst)
    {
        // Memory allocation error.
        hr = E_OUTOFMEMORY;
        goto Exit;
    }

    // Populate this structure
    memset(pst, 0, dwSize);
    pst->cbSize = dwSize;
    pst->dwParams = SIM_PARAM_SIMTEXT_FLAGS;

    // Min and max response
    if ((dwNotifyCode == SIM_NOTIFY_GETINPUT) || (dwNotifyCode == SIM_NOTIFY_GETINKEY))
    {
        pst->dwParams |= (SIM_PARAM_SIMTEXT_MINRESPONSE | SIM_PARAM_SIMTEXT_MAXRESPONSE);
        pst->dwMinResponse = m_dwMinResponse;
        pst->dwMaxResponse = m_dwMaxResponse;
    }

    // The value of the fifth byte is different between DISPLAY TEXT and GET INKEY
    // DISPLAY TEXT also has the optional immediate response setting.
    pst->dwFlags = 0;
    if (dwNotifyCode == SIM_NOTIFY_DISPLAYTEXT)
    {
        if (bFifthByte & 0x01)
        {
            pst->dwFlags |= SIMTEXT_HIGHPRIORITY;
        }
        if (!(bFifthByte & 0x80))
        {
            pst->dwFlags |= SIMTEXT_DELAYCLEAR;
        }
        if (m_fImmediateResponse)
        {
            pst->dwFlags |= SIMTEXT_IMMEDIATERESPONSE;
        }
    }
    else
    {
        // GET INPUT and GET INKEY -- first two bits tell us what characters can be input
        if (!(bFifthByte & 0x01))
        {
            pst->dwFlags |= SIMTEXT_KEYPADDIGITS;
        }
        else if (!(bFifthByte & 0x02))
        {
            pst->dwFlags |= SIMTEXT_GSMDEFAULTALPHABET;
        }

        if (bFifthByte & 0x80)
        {
            pst->dwFlags |= SIMTEXT_HELPINFO;
        }

        if (dwNotifyCode == SIM_NOTIFY_GETINPUT)
        {
            if (bFifthByte & 0x04)
            {
                pst->dwFlags |= SIMTEXT_NOECHO;
            }
            if (bFifthByte & 0x08)
            {
                pst->dwFlags |= SIMTEXT_PACKEDRESPONSE;
            }
        }
        else if (dwNotifyCode == SIM_NOTIFY_GETINKEY)
        {
            if (bFifthByte & 0x04)
            {
                pst->dwFlags |= SIMTEXT_YESNO;
            }
        }
    }

    // Is there specified text? A null text string is valid and will be marked
    // by having a text length of zero.
    if (m_dwTextLen)
    {
        pst->dwParams |= SIM_PARAM_SIMTEXT_TEXTSIZE | SIM_PARAM_SIMTEXT_TEXTOFFSET;
        pst->dwTextSize = m_dwTextLen;
        pst->dwTextOffset = ROUNDTODWORD(sizeof(SIMTEXT));
        lstrcpy(((TCHAR *) ((LPBYTE) pst + pst->dwTextOffset)), m_pwszText);
    }

    // Is there default text?
    if (m_dwDefaultTextLen)
    {
        pst->dwParams |= (SIM_PARAM_SIMTEXT_DEFAULTTEXTOFFSET | SIM_PARAM_SIMTEXT_DEFAULTTEXTSIZE);
        pst->dwDefaultTextSize = m_dwDefaultTextLen;
        pst->dwDefaultTextOffset = pst->dwTextOffset + ROUNDTODWORD(pst->dwTextSize);
        lstrcpy(((TCHAR *) ((LPBYTE) pst + pst->dwDefaultTextOffset)), m_pwszDefaultText);
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconIdentifier)
    {
        pst->dwParams |= SIM_PARAM_SIMTEXT_ICONID;
        pst->dwIconIdentifier = m_dwIconIdentifier;
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconQualifier)
    {
        pst->dwParams |= SIM_PARAM_SIMTEXT_ICONQUALIFIER;
        pst->dwIconQualifier = m_dwIconQualifier;
    }

    *lpdwSize = dwSize;
    
Exit:
    
    *ppbResult = (LPBYTE) pst;
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::BuildSIMTEXT\r\n")));
    return hr;
}

/****************************************************************************

    FUNCTION:   BuildSIMTONE

    PURPOSE:    Builds the SIMTONE structure

    PARAMETERS: dwNotifyCode - Which command is this?
                bFifthByte - The fifth byte from the command details
                ppbResult - OUT parameter to hold allocated structure

    RETURNS:    HRESULT

****************************************************************************/

HRESULT CRilSimToolkitCommand::BuildSIMTONE(DWORD dwNotifyCode, BYTE bFifthByte, LPBYTE *ppbResult, DWORD *lpdwSize)
{
    SIMTONE *pst = NULL;
    HRESULT hr = S_OK;
    DWORD dwSize;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMTONE\r\n")));

    dwNotifyCode;  // Avoid warning C4100: unreferenced formal parameter
    bFifthByte;    // Avoid warning C4100: unreferenced formal parameter

    // OK, let's see how much space we need now
    dwSize = ROUNDTODWORD(sizeof(SIMTONE)) + ROUNDTODWORD(m_dwAlphaIdLen);
    pst = (SIMTONE *) new BYTE[dwSize];
    if (!pst)
    {
        // Oops
        hr = E_OUTOFMEMORY;
        goto Exit;
    }

    memset(pst, 0, dwSize);
    pst->cbSize = dwSize;
    pst->dwParams = SIM_PARAM_SIMTONE_DURATION | SIM_PARAM_SIMTONE_TONE;
    pst->dwTone = m_dwTone;
    pst->dwDuration = m_dwDuration;
    if (m_dwAlphaIdLen)
    {
        pst->dwParams |= (SIM_PARAM_SIMTONE_TEXTSIZE | SIM_PARAM_SIMTONE_TEXTOFFSET);
        pst->dwTextSize = m_dwAlphaIdLen;
        pst->dwTextOffset = ROUNDTODWORD(sizeof(SIMTONE));
        lstrcpy(((TCHAR *) ((LPBYTE) pst + pst->dwTextOffset)), m_pwszAlphaId);
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconIdentifier)
    {
        pst->dwParams |= SIM_PARAM_SIMTONE_ICONID;
        pst->dwIconIdentifier = m_dwIconIdentifier;
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconQualifier)
    {
        pst->dwParams |= SIM_PARAM_SIMTONE_ICONQUALIFIER;
        pst->dwIconQualifier = m_dwIconQualifier;
    }

    *lpdwSize = dwSize;

Exit:
    *ppbResult = (LPBYTE) pst;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::BuildSIMTONE\r\n")));
    return hr;
}

/****************************************************************************

    FUNCTION:   BuildSIMLOCALINFO

    PURPOSE:    Builds the SIMLOCALINFO structure

    PARAMETERS: dwNotifyCode - Which command is this?
                bFifthByte - The fifth byte from the command details
                ppbResult - OUT parameter to hold allocated structure

    RETURNS:    HRESULT

****************************************************************************/

HRESULT CRilSimToolkitCommand::BuildSIMLOCALINFO(DWORD dwNotifyCode, BYTE bFifthByte, LPBYTE *ppbResult, DWORD *lpdwSize)
{
    DWORD *pdw = NULL;
    HRESULT hr = S_OK;
    const DWORD rgdwInfoType[] = { SIMLOCALINFO_LOCATION, SIMLOCALINFO_IMEI, SIMLOCALINFO_NMR };

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMLOCALINFO\r\n")));

    dwNotifyCode;  // Avoid warning C4100: unreferenced formal parameter

    // The fifth byte needs to be 0, 1, or 2
    if (bFifthByte > 0x02)
    {
        hr = E_FAIL;
        goto Exit;
    }

    // Now we can allocate memory
    pdw = new DWORD;
    if (!pdw)
    {
        hr = E_OUTOFMEMORY;
        goto Exit;
    }

    // Everything is in that fifth byte
    *pdw = rgdwInfoType[bFifthByte];
    *lpdwSize = sizeof(DWORD);

Exit:
    *ppbResult = (LPBYTE) pdw;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::BuildSIMLOCALINFO\r\n")));
    return hr;
}


/****************************************************************************

    FUNCTION:   BuildSIMPOLLINGINTERVAL

    PURPOSE:    Builds the SIMPOLLINGINTERVAL structure

    PARAMETERS: dwNotifyCode - Which command is this?
                bFifthByte - The fifth byte from the command details
                ppbResult - OUT parameter to hold allocated structure

    RETURNS:    HRESULT

****************************************************************************/

HRESULT CRilSimToolkitCommand::BuildSIMPOLLINGINTERVAL(DWORD dwNotifyCode, BYTE bFifthByte, LPBYTE *ppbResult, DWORD *lpdwSize)
{
    DWORD *pdw = NULL;
    HRESULT hr = S_OK;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMPOLLINGINTERVAL\r\n")));

    dwNotifyCode;  // Avoid warning C4100: unreferenced formal parameter
    bFifthByte;  // Avoid warning C4100: unreferenced formal parameter

    // Now we can allocate memory
    pdw = new DWORD;
    if (!pdw)
    {
        hr = E_OUTOFMEMORY;
        goto Exit;
    }

    *pdw = m_dwDuration;
    *lpdwSize = sizeof(DWORD);

Exit:
    *ppbResult = (LPBYTE) pdw;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::BuildSIMPOLLINGINTERVAL\r\n")));
    return hr;
}

/****************************************************************************

    FUNCTION:   BuildSIMCALL

    PURPOSE:    Builds the SIMCALL structure

    PARAMETERS: dwNotifyCode - Which command is this?
                bFifthByte - The fifth byte from the command details
                ppbResult - OUT parameter to hold allocated structure

    RETURNS:    HRESULT

****************************************************************************/

HRESULT CRilSimToolkitCommand::BuildSIMCALL(DWORD dwNotifyCode, BYTE bFifthByte, LPBYTE *ppbResult, DWORD *lpdwSize)
{
    HRESULT hr = S_OK;
    SIMCALL *psc = NULL;
    DWORD dwSize;
    BYTE bCallFlags;
    DWORD dwUsedSize;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMCALL\r\n")));

    dwNotifyCode;  // Avoid warning C4100: unreferenced formal parameter

    // OK, let's put everything together here
    dwSize = ROUNDTODWORD(sizeof(SIMCALL)) + ROUNDTODWORD(m_dwAlphaIdLen) +
                ROUNDTODWORD(m_dwAddressLen) + ROUNDTODWORD(m_dwSubAddrLen) +
                ROUNDTODWORD(m_dwAlphaId2Len);
    psc = (SIMCALL *) new BYTE[dwSize];
    if (!psc)
    {
        hr = E_OUTOFMEMORY;
        goto Exit;
    }

    memset(psc, 0, dwSize);
    psc->cbSize = dwSize;
    psc->dwParams = SIM_PARAM_SIMCALL_FLAGS;
    psc->dwFlags = 0;
    if (bFifthByte & 0x01)
    {
        // This means use redial
        psc->dwFlags |= SIMCALL_REDIAL;
    }
    bCallFlags = (BYTE) ((bFifthByte >> 1) & 0x03);
    if (bCallFlags == 0x02)
    {
        psc->dwFlags |= SIMCALL_DISCONNECTCALLS;
    }
    else if (bCallFlags == 0x01)
    {
        psc->dwFlags |= SIMCALL_HOLDCALLS;
    }
    else
    {
        ASSERT(bCallFlags == 0x00);
        psc->dwFlags |= SIMCALL_IDLE;
    }

    // Do we have a redial duration?
    if (m_dwDuration != SIMTONE_DEFAULTDURATION)
    {
        psc->dwParams |= SIM_PARAM_SIMCALL_REDIALDURATION;
        psc->dwRedialDuration = m_dwDuration;
    }

    dwUsedSize = ROUNDTODWORD(sizeof(SIMCALL));
    if (m_dwAddressLen)
    {
        psc->dwParams |= ( SIM_PARAM_SIMCALL_ADDRESSOFFSET | SIM_PARAM_SIMCALL_ADDRESSSIZE |
                           SIM_PARAM_SIMCALL_ADDRESSTYPE | SIM_PARAM_SIMCALL_NUMPLAN);
        psc->dwNumPlan = m_dwNumPlan;
        psc->dwAddressType = m_dwAddrType;
        psc->dwAddressSize = m_dwAddressLen;
        psc->dwAddressOffset = dwUsedSize;
        lstrcpy(((TCHAR *) ((LPBYTE) psc + psc->dwAddressOffset)), m_pwszAddress);
        dwUsedSize += ROUNDTODWORD(m_dwAddressLen);
    }

    // Set up the User Confirmation text string, if it's there
    if (m_dwAlphaIdLen)
    {
        psc->dwParams |= (SIM_PARAM_SIMCALL_TEXTSIZE | SIM_PARAM_SIMCALL_TEXTOFFSET);
        psc->dwTextSize = m_dwAlphaIdLen;
        psc->dwTextOffset = dwUsedSize;
        lstrcpy(((TCHAR *) ((LPBYTE) psc + psc->dwTextOffset)), m_pwszAlphaId);
        dwUsedSize += ROUNDTODWORD(m_dwAlphaIdLen);
    }

    // And finally the subaddress, if it's there
    if (m_dwSubAddrLen)
    {
        psc->dwParams |= (SIM_PARAM_SIMCALL_SUBADDRESSSIZE | SIM_PARAM_SIMCALL_SUBADDRESSOFFSET);
        psc->dwSubAddrSize = m_dwSubAddrLen;
        psc->dwSubAddrOffset = dwUsedSize;
        lstrcpy(((TCHAR *) ((LPBYTE) psc + psc->dwSubAddrOffset)), m_pwszSubAddr);
        dwUsedSize += ROUNDTODWORD(m_dwSubAddrLen);
    }

    // Set up the Call Setup text string, if it's there
    if (m_dwAlphaId2Len)
    {
        psc->dwParams |= (SIM_PARAM_SIMCALL_CALLSETUPTEXTSIZE | SIM_PARAM_SIMCALL_CALLSETUPTEXTOFFSET);
        psc->dwCallSetupTextSize = m_dwAlphaId2Len;
        psc->dwCallSetupTextOffset = dwUsedSize;
        lstrcpy(((TCHAR *) ((LPBYTE) psc + psc->dwCallSetupTextOffset)), m_pwszAlphaId2);
        dwUsedSize += ROUNDTODWORD(m_dwAlphaId2Len);
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconIdentifier)
    {
        psc->dwParams |= SIM_PARAM_SIMCALL_ICONID;
        psc->dwIconIdentifier = m_dwIconIdentifier;
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconQualifier)
    {
        psc->dwParams |= SIM_PARAM_SIMCALL_ICONQUALIFIER;
        psc->dwIconQualifier = m_dwIconQualifier;
    }

    // Call Setup Phase Icon
    if (SIMTKIT_INVALID_VALUE != m_dwIconIdentifier2)
    {
        psc->dwParams |= SIM_PARAM_SIMCALL_CALLSETUPICONID;
        psc->dwCallSetupIconIdentifier = m_dwIconIdentifier2;
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconQualifier2)
    {
        psc->dwParams |= SIM_PARAM_SIMCALL_CALLSETUPICONQUALIFIER;
        psc->dwCallSetupIconQualifier = m_dwIconQualifier2;
    }

    *lpdwSize = dwSize;

Exit:
    *ppbResult = (LPBYTE) psc;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMCALL\r\n")));
    return hr;
}

/****************************************************************************

    FUNCTION:   BuildSIMREFRESH

    PURPOSE:    Builds the SIMREFRESH structure

    PARAMETERS: dwNotifyCode - Which command is this?
                bFifthByte - The fifth byte from the command details
                ppbResult - OUT parameter to hold allocated structure

    RETURNS:    HRESULT

****************************************************************************/

HRESULT CRilSimToolkitCommand::BuildSIMREFRESH(DWORD dwNotifyCode, BYTE bFifthByte, LPBYTE *ppbResult, DWORD *lpdwSize)
{
    HRESULT hr = S_OK;
    SIMFILEREFRESH *psfr = NULL;
    const DWORD rgdwFlags[] = { (SIMFILE_SIMINIT | SIMFILE_FULLFILECHANGE), SIMFILE_FILECHANGE,
                                (SIMFILE_SIMINIT | SIMFILE_FILECHANGE), SIMFILE_SIMINIT,
                                SIMFILE_SIMRESET };

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMREFRESH\r\n")));

    dwNotifyCode;  // Avoid warning C4100: unreferenced formal parameter

    // Check parameters
    // If the Refresh command qualifier (Refresh Mode) is "File Change Notification"/0x01 or
    // "SIM Initialization and File Change Notification"/0x02 then there should be a list of files.
    // if (((bFifthByte == 0x01) || (bFifthByte == 0x02)) && !m_dwNumFiles)
    if (((bFifthByte == 0x01) || (bFifthByte == 0x02))&& m_dwNumFiles)            //Modify by zxn for DF
    {
        // This isn't allowed
        hr = E_INVALIDARG;
        goto Exit;
    }
    else if (bFifthByte >= 0x05)
    {
        // 0x05 through 0xFF are reserved values, proper response is "Command type not understood".
        // Return an hresult, so that calling functions can pick up and send the proper result.
        hr = E_FAIL;
        goto Exit;
    }
    //For SIM reset event, WM6 needs to restore state.
    if( bFifthByte == 4 )
    {
         RETAILMSG(MSG_ON,(TEXT("STK Event: SIM reset...\r\n")));
         HANDLE hThread = NULL;
         hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)RIL_RestoreStateProc, NULL, 0, NULL);
         if (hThread)
         {
             // no need to keep track of it
             CloseHandle(hThread);
             hThread = NULL;
         }
         else
         {
             RETAILMSG(MSG_ON, (TEXT("RIL: Error CreateThread with start address RIL_RestoreStateProc!\r\n")));
         }
    }
    
    if (MAX_FILES < m_dwNumFiles)
    {
        hr=E_FAIL;
        goto Exit;
    }

    // OK, let's put everything together here
    psfr = (SIMFILEREFRESH *) new SIMFILEREFRESH;
    if (!psfr)
    {
        hr = E_OUTOFMEMORY;
        goto Exit;
    }

    memset(psfr, 0, sizeof(SIMFILEREFRESH));
    psfr->cbSize = sizeof(SIMFILEREFRESH);
    if (bFifthByte < 0x05)
    {
        // Flags were specified
        psfr->dwParams |= SIM_PARAM_FILEREFRESH_FLAGS;
        psfr->dwFlags = rgdwFlags[bFifthByte];
    }
    // All right, do we have a list of files?
    if (m_dwNumFiles)
    {
        psfr->dwParams |= (SIM_PARAM_FILEREFRESH_FILECOUNT | SIM_PARAM_FILEREFRESH_FILEARRAY);
        psfr->dwFileCount = m_dwNumFiles;
        memcpy(psfr->rgdwAddress, m_pdwFiles, m_dwNumFiles * sizeof(DWORD));
    }

    *lpdwSize = sizeof(SIMFILEREFRESH);

Exit:
    *ppbResult = (LPBYTE) psfr;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::BuildSIMREFRESH\r\n")));
    return hr;
}

/****************************************************************************

    FUNCTION:   BuildSIMUSSD

    PURPOSE:    Builds the SIMUSSD structure

    PARAMETERS: dwNotifyCode - Which command is this?
                bFifthByte - The fifth byte from the command details
                ppbResult - OUT parameter to hold allocated structure

    RETURNS:    HRESULT

****************************************************************************/

HRESULT CRilSimToolkitCommand::BuildSIMUSSD(DWORD dwNotifyCode, BYTE bFifthByte, LPBYTE *ppbResult, DWORD *lpdwSize)
{
    HRESULT hr = S_OK;
    SIMUSSD *psu = NULL;
    DWORD dwSize;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMUSSD\r\n")));

    dwNotifyCode;  // Avoid warning C4100: unreferenced formal parameter
    bFifthByte;    // Avoid warning C4100: unreferenced formal parameter

    // OK, let's put everything together here
    dwSize = ROUNDTODWORD(sizeof(SIMUSSD)) + ROUNDTODWORD(m_dwAlphaIdLen) + ROUNDTODWORD(m_dwUSSDLen);

    if ( dwSize == 0 )
    {
        hr = E_ABORT;
        goto Exit;
    }

    psu = (SIMUSSD *) new BYTE[dwSize];
    if (!psu)
    {
        hr = E_OUTOFMEMORY;
        goto Exit;
    }

    memset(psu, 0, dwSize);
    psu->cbSize = dwSize;

    // Set the num plan and address type
    if ( m_dwAddrType != SIM_ADDRTYPE_UNKNOWN)
    {
        psu->dwParams |= SIM_PARAM_SIMUSSD_ADDRESSTYPE;
        psu->dwAddressType = m_dwAddrType;
    }
    else
    {
        psu->dwAddressType = SIM_ADDRTYPE_UNKNOWN;
    }

    if (m_dwNumPlan != SIM_NUMPLAN_UNKNOWN)
    {
        psu->dwParams |= SIM_PARAM_SIMUSSD_NUMPLAN;
        psu->dwNumPlan = m_dwNumPlan;
    }
    else
    {
        psu->dwNumPlan = SIM_NUMPLAN_UNKNOWN;
    }

    // Only add the USSD string if it exists.
    if (m_dwUSSDLen)
    {
        // Shouldn't be here unless we've got something to send.
        ASSERT( NULL != m_pwszUSSD );
        ASSERT( m_dwUSSDLen > 0 );

        psu->dwParams |= SIM_PARAM_SIMUSSD_USSDOFFSET | SIM_PARAM_SIMUSSD_USSDSIZE;
        // Now add the USSD string of bytes (which was required)
        psu->dwUSSDSize = m_dwUSSDLen;
        psu->dwUSSDOffset = ROUNDTODWORD(sizeof(SIMUSSD));
        lstrcpy(((TCHAR *) ((LPBYTE) psu + psu->dwUSSDOffset)), m_pwszUSSD);
    }

    // Set up the text string, if it's there
    if (m_dwAlphaIdLen)
    {
        psu->dwParams |= (SIM_PARAM_SIMUSSD_TEXTSIZE | SIM_PARAM_SIMUSSD_TEXTOFFSET);
        psu->dwTextSize = m_dwAlphaIdLen;
        psu->dwTextOffset = ROUNDTODWORD(sizeof(SIMUSSD)) + ROUNDTODWORD(m_dwUSSDLen);
        lstrcpy(((TCHAR *) ((LPBYTE) psu + psu->dwTextOffset)), m_pwszAlphaId);
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconIdentifier)
    {
        psu->dwParams |= SIM_PARAM_SIMUSSD_ICONID;
        psu->dwIconIdentifier = m_dwIconIdentifier;
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconQualifier)
    {
        psu->dwParams |= SIM_PARAM_SIMUSSD_ICONQUALIFIER;
        psu->dwIconQualifier = m_dwIconQualifier;
    }

    *lpdwSize = dwSize;

Exit:
    *ppbResult = (LPBYTE) psu;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::BuildSIMUSSD\r\n")));
    return hr;
}

/****************************************************************************

    FUNCTION:   BuildSIMSMS

    PURPOSE:    Builds the SIMSMS structure

    PARAMETERS: dwNotifyCode - Which command is this?
                bFifthByte - The fifth byte from the command details
                ppbResult - OUT parameter to hold allocated structure

    RETURNS:    HRESULT

****************************************************************************/

HRESULT CRilSimToolkitCommand::BuildSIMSMS(DWORD dwNotifyCode, BYTE bFifthByte, LPBYTE *ppbResult, DWORD *lpdwSize)
{
    HRESULT hr = S_OK;
    SIMSMS *pss = NULL;
    DWORD dwSize;
    unsigned int uiSize;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMSMS\r\n")));

    dwNotifyCode;  // Avoid warning C4100: unreferenced formal parameter
    bFifthByte;    // Avoid warning C4100: unreferenced formal parameter

    // OK, let's put everything together here
    BOOL fSafeDword = FALSE;
    if ( TRUE == safeIntUAdd( ROUNDTODWORD(sizeof(SIMSMS)),ROUNDTODWORD(m_dwAlphaIdLen), &uiSize ))
    {
        if ( TRUE == safeIntUAdd( uiSize, ROUNDTODWORD(m_dwAddressLen), &uiSize ))
        {
            fSafeDword = safeIntUAdd( uiSize, ROUNDTODWORD(m_dwTPDULen), &uiSize );
        }
    }
    if ( FALSE == fSafeDword )
    {
        hr = E_ABORT;
        goto Exit;
    }
    else
    {
        dwSize = uiSize;
    }

    if ( dwSize == 0 )
    {
        hr = E_ABORT;
        goto Exit;
    }

    pss = (SIMSMS *) new BYTE[dwSize];
    if (!pss)
    {
        hr = E_OUTOFMEMORY;
        goto Exit;
    }

    memset(pss, 0, dwSize);
    pss->cbSize = dwSize;
    pss->dwParams = SIM_PARAM_SIMSMS_FLAGS;
    pss->dwFlags = 0;

    if (m_dwTPDULen)
    {
        pss->dwParams |= (SIM_PARAM_SIMSMS_TPDUOFFSET | SIM_PARAM_SIMSMS_TPDUSIZE);
        // Now, set the TPDU bytes
        pss->dwTPDUSize = m_dwTPDULen;
        pss->dwTPDUOffset = ROUNDTODWORD(sizeof(SIMSMS));
        memcpy(((LPBYTE *) ((LPBYTE) pss + pss->dwTPDUOffset)), m_lpbTPDU, m_dwTPDULen);
    }

    // Set up the text string, if it's there
    if (m_dwAlphaIdLen)
    {
        pss->dwParams |= (SIM_PARAM_SIMSMS_TEXTSIZE | SIM_PARAM_SIMSMS_TEXTOFFSET);
        pss->dwTextSize = m_dwAlphaIdLen;
        pss->dwTextOffset = ROUNDTODWORD(sizeof(SIMSMS)) + ROUNDTODWORD(m_dwTPDULen);
        lstrcpy(((TCHAR *) ((LPBYTE) pss + pss->dwTextOffset)), m_pwszAlphaId);
    }

    // And finally the address, if it's there
    if (m_dwAddressLen)
    {
        // OK, the address needs to be there
        pss->dwParams |= (SIM_PARAM_SIMSMS_NUMPLAN | SIM_PARAM_SIMSMS_ADDRESSTYPE
                            | SIM_PARAM_SIMSMS_ADDRESSSIZE | SIM_PARAM_SIMSMS_ADDRESSOFFSET);
        pss->dwNumPlan = m_dwNumPlan;
        pss->dwAddressType = m_dwAddrType;
        pss->dwAddressSize = m_dwAddressLen;
        pss->dwAddressOffset = ROUNDTODWORD(sizeof(SIMSMS)) + ROUNDTODWORD(m_dwTPDULen) + ROUNDTODWORD(m_dwAlphaIdLen);
        lstrcpy(((TCHAR *) ((LPBYTE) pss + pss->dwAddressOffset)), m_pwszAddress);
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconIdentifier)
    {
        pss->dwParams |= SIM_PARAM_SIMSMS_ICONID;
        pss->dwIconIdentifier = m_dwIconIdentifier;
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconQualifier)
    {
        pss->dwParams |= SIM_PARAM_SIMSMS_ICONQUALIFIER;
        pss->dwIconQualifier = m_dwIconQualifier;
    }

    *lpdwSize = dwSize;

Exit:
    *ppbResult = (LPBYTE) pss;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMSMS\r\n")));
    return hr;
}


/****************************************************************************

    FUNCTION:   BuildSIMEVENTLIST

    PURPOSE:    Builds the SIMEVENTLIST structure

    PARAMETERS: dwNotifyCode - Which command is this?
                bFifthByte - The fifth byte from the command details
                ppbResult - OUT parameter to hold allocated structure

    RETURNS:    HRESULT

****************************************************************************/

HRESULT CRilSimToolkitCommand::BuildSIMEVENTLIST(DWORD dwNotifyCode, BYTE bFifthByte, LPBYTE *ppbResult, DWORD *lpdwSize)
{
    SIMEVENTLIST *psel = NULL;
    HRESULT hr = S_OK;
    DWORD dwSize;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMEVENTLIST\r\n")));

    dwNotifyCode;  // Avoid warning C4100: unreferenced formal parameter
    bFifthByte;    // Avoid warning C4100: unreferenced formal parameter

    // OK, let's see how much space we need now
    dwSize = ROUNDTODWORD(sizeof(SIMEVENTLIST)) + ROUNDTODWORD(m_dwEventListLen);

    if ( dwSize == 0 )
    {
        hr = E_ABORT;
        goto Exit;
    }

    psel = (SIMEVENTLIST *) new BYTE[dwSize];
    if (!psel)
    {
        DEBUGCHK(FALSE);
        hr = E_OUTOFMEMORY;
        goto Exit;
    }

    memset(psel, 0, dwSize);
    psel->cbSize = dwSize;

    DEBUGCHK(0 < m_dwEventListLen);
    DEBUGCHK(NULL != m_lpbEventList);

    if (m_dwEventListLen && m_lpbEventList)
    {
        psel->dwParams = SIM_PARAM_SIMEVENTLIST_EVENTSSIZE | SIM_PARAM_SIMEVENTLIST_EVENTSOFFSET;
        psel->dwEventsSize = m_dwEventListLen;
        psel->dwEventsOffset= ROUNDTODWORD(sizeof(SIMEVENTLIST));
        memcpy(((LPBYTE *) ((LPBYTE) psel + psel->dwEventsOffset)), m_lpbEventList, m_dwEventListLen);
    }

    *lpdwSize = dwSize;

Exit:
    *ppbResult = (LPBYTE) psel;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::BuildSIMEVENTLIST\r\n")));
    return hr;
}


/****************************************************************************

    FUNCTION:   BuildSIMLAUNCHBROWSER

    PURPOSE:    Builds the SIMLAUNCHBROWSER structure

    PARAMETERS: dwNotifyCode - Which command is this?
                bFifthByte - The fifth byte from the command details
                ppbResult - OUT parameter to hold allocated structure

    RETURNS:    HRESULT

****************************************************************************/
HRESULT CRilSimToolkitCommand::BuildSIMLAUNCHBROWSER(DWORD dwNotifyCode, BYTE bFifthByte, LPBYTE *ppbResult, DWORD *lpdwSize)
{
    SIMLAUNCHBROWSER *pslb = NULL;
    SIMFILEREFERENCE *psfr;
    HRESULT hr = S_OK;
    DWORD dwUsedSize;
    DWORD dwSize;
    DWORD i;
    DWORD cbFileSize;
    unsigned int uiSize;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMLAUNCHBROWSER\r\n")));

    dwNotifyCode;  // Avoid warning C4100: unreferenced formal parameter

    // How much space do we need to allocate?
    BOOL fSafeDword = FALSE;
    if ( TRUE == safeIntUAdd( ROUNDTODWORD(sizeof(SIMLAUNCHBROWSER)),ROUNDTODWORD(m_dwAlphaIdLen), &uiSize ))
    {
        if ( TRUE == safeIntUAdd( uiSize, ROUNDTODWORD(m_dwURLLen), &uiSize ))
        {
            if ( TRUE == safeIntUAdd( uiSize, ROUNDTODWORD(m_dwBearerLen), &uiSize ))
            {
                if ( TRUE == safeIntUAdd( uiSize, ROUNDTODWORD(m_dwTextLen), &uiSize))
                {
                    for (i = 0, fSafeDword = TRUE; (i < m_numpsfr) && (TRUE == fSafeDword); i++)
                    {
                        fSafeDword = safeIntUAdd( uiSize, ROUNDTODWORD(m_rgpsfr[i]->cbSize), &uiSize);
                    }
                }
            }
        }
    }
    if ( FALSE == fSafeDword )
    {
        hr = E_ABORT;
        goto Exit;
    }
    else
    {
        dwSize = uiSize;
    }


    pslb = (SIMLAUNCHBROWSER *) new BYTE[dwSize];
    if (!pslb)
    {
        hr = E_OUTOFMEMORY;
        goto Exit;
    }

    // Populate this structure
    memset(pslb, 0, dwSize);
    pslb->cbSize = dwSize;
    dwUsedSize = ROUNDTODWORD(sizeof(SIMLAUNCHBROWSER));

    pslb->dwParams |= SIM_PARAM_SIMLAUNCHBROWSER_FLAGS;
    pslb->dwFlags = bFifthByte;

    if (m_dwBrowserId != -1)
    {
        pslb->dwParams |= SIM_PARAM_SIMLAUNCHBROWSER_BROWSERID;
        pslb->dwBrowserId = m_dwBrowserId;
    }

    if (m_dwURLLen)
    {
        pslb->dwParams |= (SIM_PARAM_SIMLAUNCHBROWSER_URLSIZE | SIM_PARAM_SIMLAUNCHBROWSER_URLOFFSET);
        pslb->dwURLSize = m_dwURLLen;
        pslb->dwURLOffset = dwUsedSize;
        lstrcpy(((TCHAR *) ((LPBYTE) pslb + pslb->dwURLOffset)), m_pwszURL);
        dwUsedSize += ROUNDTODWORD(m_dwURLLen);
    }

    if (m_dwBearerLen)
    {
        pslb->dwParams |= (SIM_PARAM_SIMLAUNCHBROWSER_BEARERSIZE | SIM_PARAM_SIMLAUNCHBROWSER_BEAREROFFSET);
        pslb->dwBearerSize = m_dwBearerLen;
        pslb->dwBearerOffset = dwUsedSize;
        memcpy(((LPBYTE) pslb + pslb->dwBearerOffset), m_lpbBearer, m_dwBearerLen);
        dwUsedSize += ROUNDTODWORD(m_dwBearerLen);
    }

    if (m_dwTextLen)
    {
        pslb->dwParams |= (SIM_PARAM_SIMLAUNCHBROWSER_GATEWAYSIZE | SIM_PARAM_SIMLAUNCHBROWSER_GATEWAYOFFSET);
        pslb->dwGatewaySize = m_dwTextLen;
        pslb->dwGatewayOffset = dwUsedSize;
        lstrcpy(((TCHAR *) ((LPBYTE) pslb + pslb->dwGatewayOffset)), m_pwszText);
        dwUsedSize += ROUNDTODWORD(m_dwTextLen);
    }

    if (m_dwAlphaIdLen)
    {
        pslb->dwParams |= (SIM_PARAM_SIMLAUNCHBROWSER_TEXTSIZE | SIM_PARAM_SIMLAUNCHBROWSER_TEXTOFFSET);
        pslb->dwTextSize = m_dwAlphaIdLen;
        pslb->dwTextOffset = dwUsedSize;
        lstrcpy(((TCHAR *) ((LPBYTE) pslb + pslb->dwTextOffset)), m_pwszAlphaId);
        dwUsedSize += ROUNDTODWORD(m_dwAlphaIdLen);
    }

    // Now for the Provisioning file references
    if (m_numpsfr)
    {
        pslb->dwParams |= (SIM_PARAM_SIMLAUNCHBROWSER_PROVISIONFILECOUNT |
                           SIM_PARAM_SIMLAUNCHBROWSER_PROVISIONFILESIZE  |
                           SIM_PARAM_SIMLAUNCHBROWSER_PROVISIONFILEOFFSET);
        pslb->dwProvisionFileCount = m_numpsfr;
        pslb->dwProvisionFileOffset = dwUsedSize;
        pslb->dwProvisionFileSize = dwSize - pslb->dwProvisionFileOffset;

        psfr = (SIMFILEREFERENCE *) ((LPBYTE) pslb + pslb->dwProvisionFileOffset);
        for (i = 0; i < m_numpsfr; i++)
        {
            cbFileSize = m_rgpsfr[i]->cbSize;

            memcpy(psfr, m_rgpsfr[i], cbFileSize);
            psfr = (SIMFILEREFERENCE *) ((LPBYTE) psfr + cbFileSize);
        }
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconIdentifier)
    {
        pslb->dwParams |= SIM_PARAM_SIMLAUNCHBROWSER_ICONID;
        pslb->dwIconIdentifier = m_dwIconIdentifier;
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconQualifier)
    {
        pslb->dwParams |= SIM_PARAM_SIMLAUNCHBROWSER_ICONQUALIFIER;
        pslb->dwIconQualifier = m_dwIconQualifier;
    }

    *lpdwSize = dwSize;

Exit:
    *ppbResult = (LPBYTE) pslb;
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::BuildSIMLAUNCHBROWSER\r\n")));
    return hr;
}


/****************************************************************************

    FUNCTION:   BuildSIMSENDDTMF

    PURPOSE:    Builds the SIMSENDDTMF structure

    PARAMETERS: dwNotifyCode - Which command is this?
                bFifthByte - The fifth byte from the command details
                ppbResult - OUT parameter to hold allocated structure

    RETURNS:    HRESULT

****************************************************************************/

HRESULT CRilSimToolkitCommand::BuildSIMSENDDTMF(DWORD dwNotifyCode, BYTE bFifthByte, LPBYTE *ppbResult, DWORD *lpdwSize)
{
    HRESULT hr = S_OK;
    SIMSENDDTMF *pssd = NULL;
    DWORD dwSize;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMSENDDTMF\r\n")));

    bFifthByte;    // Avoid warning C4100: unreferenced formal parameter
    dwNotifyCode;  // Avoid warning C4100: unreferenced formal parameter

    // OK, let's put everything together here
    dwSize = ROUNDTODWORD(sizeof(SIMSENDDTMF)) + ROUNDTODWORD(m_dwAlphaIdLen) +
                ROUNDTODWORD(m_dwDTMFLen);
    pssd = (SIMSENDDTMF *) new BYTE[dwSize];
    if (!pssd)
    {
        hr = E_OUTOFMEMORY;
        goto Exit;
    }

    memset(pssd, 0, dwSize);
    pssd->cbSize = dwSize;

    if (m_dwDTMFLen)
    {
        pssd->dwParams |= (SIM_PARAM_SIMSENDDTMF_DTMFOFFSET | SIM_PARAM_SIMSENDDTMF_DTMFSIZE);
        // Now, set the DTMF String
        pssd->dwDTMFSize = m_dwDTMFLen;
        pssd->dwDTMFOffset = ROUNDTODWORD(sizeof(SIMSENDDTMF));
        memcpy(((LPBYTE *) ((LPBYTE) pssd + pssd->dwDTMFOffset)), m_pwszDTMF, m_dwDTMFLen);
    }

    // Set up the text string, if it's there
    if (m_dwAlphaIdLen)
    {
        pssd->dwParams |= (SIM_PARAM_SIMSENDDTMF_TEXTSIZE | SIM_PARAM_SIMSENDDTMF_TEXTOFFSET);
        pssd->dwTextSize = m_dwAlphaIdLen;
        pssd->dwTextOffset = ROUNDTODWORD(sizeof(SIMSENDDTMF)) + ROUNDTODWORD(m_dwDTMFLen);
        lstrcpy(((TCHAR *) ((LPBYTE) pssd + pssd->dwTextOffset)), m_pwszAlphaId);
    }


    if (SIMTKIT_INVALID_VALUE != m_dwIconIdentifier)
    {
        pssd->dwParams |= SIM_PARAM_SIMSENDDTMF_ICONID;
        pssd->dwIconIdentifier = m_dwIconIdentifier;
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconQualifier)
    {
        pssd->dwParams |= SIM_PARAM_SIMSENDDTMF_ICONQUALIFIER;
        pssd->dwIconQualifier = m_dwIconQualifier;
    }
    *lpdwSize = dwSize;

Exit:
    *ppbResult = (LPBYTE) pssd;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMSENDDTMF\r\n")));
    return hr;
}

/****************************************************************************

    FUNCTION:   BuildSIMOPENCHANNEL

    PURPOSE:    Builds the SIMOPENCHANNEL structure

    PARAMETERS: dwNotifyCode - Which command is this?
                bFifthByte - The fifth byte from the command details
                ppbResult - OUT parameter to hold allocated structure

    RETURNS:    HRESULT

****************************************************************************/

HRESULT CRilSimToolkitCommand::BuildSIMOPENCHANNEL(DWORD dwNotifyCode, BYTE bFifthByte, LPBYTE *ppbResult, DWORD *lpdwSize)
{
    HRESULT hr = S_OK;
    SIMOPENCHANNEL *psoc = NULL;
    DWORD dwUsedSize;
    DWORD dwSize;
    unsigned int uiSize;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMOPENCHANNEL\r\n")));

    bFifthByte;    // Avoid warning C4100: unreferenced formal parameter
    dwNotifyCode;  // Avoid warning C4100: unreferenced formal parameter

    // OK, let's put everything together here
    BOOL fSafeDword = FALSE;
    if ( TRUE == safeIntUAdd( ROUNDTODWORD(sizeof(SIMOPENCHANNEL)),ROUNDTODWORD(m_dwAlphaIdLen), &uiSize ))
    {
        if ( TRUE == safeIntUAdd(uiSize, ROUNDTODWORD(m_dwBearerDescLen),&uiSize))
        {
            if ( TRUE == safeIntUAdd(uiSize, ROUNDTODWORD(m_dwAddressLen),&uiSize))
            {
                if ( TRUE == safeIntUAdd(uiSize, ROUNDTODWORD(m_dwSubAddrLen),&uiSize))
                {
                    if ( TRUE == safeIntUAdd(uiSize, ROUNDTODWORD(m_dwLocalAddrLen),&uiSize))
                    {
                        if ( TRUE == safeIntUAdd(uiSize, ROUNDTODWORD(m_dwDestAddrLen),&uiSize))
                        {
                            if( TRUE == safeIntUAdd(uiSize, ROUNDTODWORD(m_dwLoginLen),&uiSize))
                            {
                                if ( TRUE == safeIntUAdd(uiSize, ROUNDTODWORD(m_dwPasswordLen),&uiSize))
                                {
                                    fSafeDword = safeIntUAdd(uiSize, ROUNDTODWORD(m_dwAccessNameLen),&uiSize);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    if ( FALSE == fSafeDword )
    {
        hr = E_ABORT;
        goto Exit;
    }
    else
    {
        dwSize = uiSize;
    }

    if ( dwSize == 0 )
    {
        hr = E_ABORT;
        goto Exit;
    }

    psoc = (SIMOPENCHANNEL *) new BYTE[dwSize];
    if (!psoc)
    {
        hr = E_OUTOFMEMORY;
        goto Exit;
    }

    memset(psoc, 0, dwSize);
    psoc->cbSize = dwSize;
    psoc->dwFlags = SIM_PARAM_SIMOPENCHANNEL_FLAGS;
    dwUsedSize = ROUNDTODWORD(sizeof(SIMOPENCHANNEL));

    // Determine link establishment priority.
    if (bFifthByte & 0x01)
    {
        // Immediate link establishment
        psoc->dwFlags |= SIMOPENCHANNEL_IMMEDIATE;
    }

    // Determine reconnection settings
    if (bFifthByte & 0x02)
    {
        psoc->dwFlags |= SIMOPENCHANNEL_AUTORECONNECT;
    }

    if (0 < m_dwBufferSize)
    {
        psoc->dwParams |= SIM_PARAM_SIMOPENCHANNEL_BUFFERSIZE;
        psoc->dwBufferSize = m_dwBufferSize;
    }

    if (SIMOPENCHANNEL_DEFAULTDURATION != m_dwDuration)
    {
        psoc->dwParams |= SIM_PARAM_SIMOPENCHANNEL_DURATION1;
        psoc->dwDuration1 = m_dwDuration;
    }

    if (SIMOPENCHANNEL_DEFAULTDURATION != m_dwDuration2)
    {
        psoc->dwParams |= SIM_PARAM_SIMOPENCHANNEL_DURATION2;
        psoc->dwDuration2 = m_dwDuration2;
    }

    if (0 < m_dwProtocolType)
    {
        psoc->dwParams |= SIM_PARAM_SIMOPENCHANNEL_PROTOCOLTYPE;
        psoc->dwProtocolType = m_dwProtocolType;
    }

    if (0 < m_dwPortNum)
    {
        psoc->dwParams |= SIM_PARAM_SIMOPENCHANNEL_PORTNUM;
        psoc->dwPortNum = m_dwPortNum;
    }
    // Set up the text string, if it's there
    if (m_dwAlphaIdLen)
    {
        psoc->dwParams |= (SIM_PARAM_SIMOPENCHANNEL_TEXTSIZE | SIM_PARAM_SIMOPENCHANNEL_TEXTOFFSET);
        psoc->dwTextSize = m_dwAlphaIdLen;
        psoc->dwTextOffset =dwUsedSize;
        lstrcpy(((TCHAR *) ((LPBYTE) psoc + psoc->dwTextOffset)), m_pwszAlphaId);
        dwUsedSize += ROUNDTODWORD(m_dwAlphaIdLen);
    }

    if (m_dwBearerDescLen)
    {
        psoc->dwParams |= (SIM_PARAM_SIMOPENCHANNEL_BEARERDESCOFFSET | SIM_PARAM_SIMOPENCHANNEL_BEARERDESCSIZE);
        psoc->dwBearerDescSize = m_dwBearerDescLen;
        psoc->dwBearerDescOffset = dwUsedSize;
        memcpy(((LPBYTE) psoc + psoc->dwBearerDescOffset), m_lpbBearerDesc, m_dwBearerDescLen);
        dwUsedSize += ROUNDTODWORD(m_dwBearerDescLen);
    }
    if (m_dwBearerDescType)
    {
        psoc->dwParams |= SIM_PARAM_SIMOPENCHANNEL_BEARERDESCTYPE;
        psoc->dwBearerDescType = m_dwBearerDescType;
    }

    if (m_dwAddressLen)
    {
        psoc->dwParams |= ( SIM_PARAM_SIMOPENCHANNEL_ADDRESSOFFSET | SIM_PARAM_SIMOPENCHANNEL_ADDRESSSIZE |
                           SIM_PARAM_SIMOPENCHANNEL_NUMPLAN | SIM_PARAM_SIMOPENCHANNEL_ADDRESSTYPE);
        psoc->dwNumPlan = m_dwNumPlan;
        psoc->dwAddressType = m_dwAddrType;
        psoc->dwAddressSize = m_dwAddressLen;
        psoc->dwAddressOffset = dwUsedSize;
        lstrcpy(((TCHAR *) ((LPBYTE) psoc + psoc->dwAddressOffset)), m_pwszAddress);
        dwUsedSize += ROUNDTODWORD(m_dwAddressLen);
    }

    if (m_dwSubAddrLen)
    {
        psoc->dwParams |= (SIM_PARAM_SIMOPENCHANNEL_SUBADDRESSOFFSET | SIM_PARAM_SIMOPENCHANNEL_SUBADDRESSSIZE);
        psoc->dwSubAddressSize = m_dwSubAddrLen;
        psoc->dwSubAddressOffset = dwUsedSize;
        lstrcpy(((TCHAR *) ((LPBYTE) psoc + psoc->dwSubAddressOffset)), m_pwszSubAddr);
        dwUsedSize += ROUNDTODWORD(m_dwSubAddrLen);
    }

    if (m_dwLocalAddrLen)
    {
        psoc->dwParams |= (SIM_PARAM_SIMOPENCHANNEL_LOCALADDROFFSET | SIM_PARAM_SIMOPENCHANNEL_LOCALADDRSIZE);
        psoc->dwLocalAddrSize = m_dwLocalAddrLen;
        psoc->dwLocalAddrOffset = dwUsedSize;
        memcpy(((LPBYTE) psoc + psoc->dwLocalAddrOffset), m_lpbLocalAddr, m_dwLocalAddrLen);
        dwUsedSize += ROUNDTODWORD(m_dwLocalAddrLen);
    }
    if (m_dwLocalAddrType)
    {
        psoc->dwParams |= SIM_PARAM_SIMOPENCHANNEL_LOCALADDRTYPE;
        psoc->dwLocalAddrType = m_dwLocalAddrType;
    }

    if (m_dwDestAddrLen)
    {
        psoc->dwParams |= (SIM_PARAM_SIMOPENCHANNEL_DESTADDROFFSET | SIM_PARAM_SIMOPENCHANNEL_DESTADDRSIZE);
        psoc->dwDestAddrSize = m_dwDestAddrLen;
        psoc->dwDestAddrOffset = dwUsedSize;
        memcpy(((LPBYTE) psoc + psoc->dwDestAddrOffset), m_lpbDestAddr, m_dwDestAddrLen);
        dwUsedSize += ROUNDTODWORD(m_dwDestAddrLen);
    }
    if (m_dwDestAddrType)
    {
        psoc->dwParams |= SIM_PARAM_SIMOPENCHANNEL_DESTADDRTYPE;
        psoc->dwDestAddrType = m_dwDestAddrType;
    }

    if (m_dwLoginLen)
    {
        psoc->dwParams |= (SIM_PARAM_SIMOPENCHANNEL_LOGINSIZE | SIM_PARAM_SIMOPENCHANNEL_LOGINOFFSET);
        psoc->dwLoginSize = m_dwLoginLen;
        psoc->dwLoginOffset = dwUsedSize;
        lstrcpy(((TCHAR *) ((LPBYTE) psoc + psoc->dwLoginOffset)), m_pwszLogin);
        dwUsedSize += ROUNDTODWORD(m_dwLoginLen);
    }

    if (m_dwPasswordLen)
    {
        psoc->dwParams |= (SIM_PARAM_SIMOPENCHANNEL_PASSWORDSIZE | SIM_PARAM_SIMOPENCHANNEL_PASSWORDOFFSET);
        psoc->dwPasswordSize = m_dwPasswordLen;
        psoc->dwPasswordOffset = dwUsedSize;
        lstrcpy(((TCHAR *) ((LPBYTE) psoc + psoc->dwPasswordOffset)), m_pwszPassword);
        dwUsedSize += ROUNDTODWORD(m_dwPasswordLen);
    }

    if (m_dwAccessNameLen)
    {
        psoc->dwParams |= (SIM_PARAM_SIMOPENCHANNEL_ACCESSNAMEOFFSET | SIM_PARAM_SIMOPENCHANNEL_ACCESSNAMESIZE);
        psoc->dwAccessNameSize = m_dwAccessNameLen;
        psoc->dwAccessNameOffset = dwUsedSize;
        memcpy(((LPBYTE) psoc + psoc->dwAccessNameOffset), m_lpbAccessName, m_dwAccessNameLen);
        dwUsedSize += ROUNDTODWORD(m_dwAccessNameLen);
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconIdentifier)
    {
        psoc->dwParams |= SIM_PARAM_SIMOPENCHANNEL_ICONID;
        psoc->dwIconIdentifier = m_dwIconIdentifier;
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconQualifier)
    {
        psoc->dwParams |= SIM_PARAM_SIMOPENCHANNEL_ICONQUALIFIER;
        psoc->dwIconQualifier = m_dwIconQualifier;
    }

    *lpdwSize = dwSize;

Exit:
    *ppbResult = (LPBYTE) psoc;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMOPENCHANNEL\r\n")));
    return hr;
}

/****************************************************************************

    FUNCTION:   BuildSIMCLOSECHANNEL

    PURPOSE:    Builds the SIMCLOSECHANNEL structure

    PARAMETERS: dwNotifyCode - Which command is this?
                bFifthByte - The fifth byte from the command details
                ppbResult - OUT parameter to hold allocated structure

    RETURNS:    HRESULT

****************************************************************************/
HRESULT CRilSimToolkitCommand::BuildSIMCLOSECHANNEL(DWORD dwNotifyCode, BYTE bFifthByte, LPBYTE *ppbResult, DWORD *lpdwSize)
{
    HRESULT hr = S_OK;
    SIMCLOSECHANNEL *pscc = NULL;
    DWORD dwSize;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMCLOSECHANNEL\r\n")));

    bFifthByte;    // Avoid warning C4100: unreferenced formal parameter
    dwNotifyCode;  // Avoid warning C4100: unreferenced formal parameter

    // OK, let's put everything together here
    dwSize = ROUNDTODWORD(sizeof(SIMCLOSECHANNEL)) + ROUNDTODWORD(m_dwAlphaIdLen);
    pscc = (SIMCLOSECHANNEL *) new BYTE[dwSize];
    if (!pscc)
    {
        hr = E_OUTOFMEMORY;
        goto Exit;
    }

    memset(pscc, 0, dwSize);
    pscc->cbSize = dwSize;

    if (m_dwDeviceDestId)
    {
        pscc->dwParams |= SIM_PARAM_SIMCLOSECHANNEL_CHANNELID;
        pscc->dwChannelId = m_dwDeviceDestId;
    }

    // Set up the text string, if it's there
    if (m_dwAlphaIdLen)
    {
        pscc->dwParams |= (SIM_PARAM_SIMCLOSECHANNEL_TEXTSIZE | SIM_PARAM_SIMCLOSECHANNEL_TEXTOFFSET);
        pscc->dwTextSize = m_dwAlphaIdLen;
        pscc->dwTextOffset = ROUNDTODWORD(sizeof(SIMCLOSECHANNEL));
        lstrcpy(((TCHAR *) ((LPBYTE) pscc + pscc->dwTextOffset)), m_pwszAlphaId);
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconIdentifier)
    {
        pscc->dwParams |= SIM_PARAM_SIMCLOSECHANNEL_ICONID;
        pscc->dwIconIdentifier = m_dwIconIdentifier;
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconQualifier)
    {
        pscc->dwParams |= SIM_PARAM_SIMCLOSECHANNEL_ICONQUALIFIER;
        pscc->dwIconQualifier = m_dwIconQualifier;
    }

    *lpdwSize = dwSize;

Exit:
    *ppbResult = (LPBYTE) pscc;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMCLOSECHANNEL\r\n")));
    return hr;
}


/****************************************************************************

    FUNCTION:   BuildSIMSENDDATA

    PURPOSE:    Builds the SIMSENDDATA structure

    PARAMETERS: dwNotifyCode - Which command is this?
                bFifthByte - The fifth byte from the command details
                ppbResult - OUT parameter to hold allocated structure

    RETURNS:    HRESULT

****************************************************************************/
HRESULT CRilSimToolkitCommand::BuildSIMSENDDATA(DWORD dwNotifyCode, BYTE bFifthByte, LPBYTE *ppbResult, DWORD *lpdwSize)
{
    HRESULT hr = S_OK;
    SIMSENDDATA *pssd = NULL;
    DWORD dwSize;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMSENDDATA\r\n")));

    dwNotifyCode;  // Avoid warning C4100: unreferenced formal parameter

    // OK, let's put everything together here
    dwSize = ROUNDTODWORD(sizeof(SIMSENDDATA)) + ROUNDTODWORD(m_dwAlphaIdLen) + ROUNDTODWORD(m_dwChannelDataLen);
    pssd = (SIMSENDDATA *) new BYTE[dwSize];
    if (!pssd)
    {
        hr = E_OUTOFMEMORY;
        goto Exit;
    }

    memset(pssd, 0, dwSize);
    pssd->cbSize = dwSize;

    pssd->dwParams |= SIM_PARAM_SIMSENDDATA_FLAGS;
    if (bFifthByte & 0x01)
    {
        pssd->dwFlags |= SIMSENDDATA_SENDIMMEDIATE;
    }
    else
    {
        pssd->dwFlags |= SIMSENDDATA_STOREDATA;
    }

    if (m_dwDeviceDestId)
    {
        pssd->dwParams |= SIM_PARAM_SIMSENDDATA_CHANNELID;
        pssd->dwChannelId = m_dwDeviceDestId;
    }

    // Set up the text string, if it's there
    if (m_dwAlphaIdLen)
    {
        pssd->dwParams |= (SIM_PARAM_SIMSENDDATA_TEXTSIZE | SIM_PARAM_SIMSENDDATA_TEXTOFFSET);
        pssd->dwTextSize = m_dwAlphaIdLen;
        pssd->dwTextOffset = ROUNDTODWORD(sizeof(SIMSENDDATA));
        lstrcpy(((TCHAR *) ((LPBYTE) pssd + pssd->dwTextOffset)), m_pwszAlphaId);
    }

    // Set up the text string, if it's there
    if (m_dwChannelDataLen)
    {
        pssd->dwParams |= (SIM_PARAM_SIMSENDDATA_CHANNELDATASIZE | SIM_PARAM_SIMSENDDATA_CHANNELDATAOFFSET);
        pssd->dwChannelDataSize= m_dwChannelDataLen;
        pssd->dwChannelDataOffset = ROUNDTODWORD(sizeof(SIMSENDDATA)) + ROUNDTODWORD(m_dwAlphaIdLen);
        memcpy(((LPBYTE) pssd + pssd->dwChannelDataOffset), m_lpbChannelData, m_dwChannelDataLen);
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconIdentifier)
    {
        pssd->dwParams |= SIM_PARAM_SIMSENDDATA_ICONID;
        pssd->dwIconIdentifier = m_dwIconIdentifier;
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconQualifier)
    {
        pssd->dwParams |= SIM_PARAM_SIMSENDDATA_ICONQUALIFIER;
        pssd->dwIconQualifier = m_dwIconQualifier;
    }

    *lpdwSize = dwSize;

Exit:
    *ppbResult = (LPBYTE) pssd;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMSENDDATA\r\n")));
    return hr;
}

/****************************************************************************

    FUNCTION:   BuildSIMRECEIVEDATA

    PURPOSE:    Builds the SIMSENDDATA structure

    PARAMETERS: dwNotifyCode - Which command is this?
                bFifthByte - The fifth byte from the command details
                ppbResult - OUT parameter to hold allocated structure

    RETURNS:    HRESULT

****************************************************************************/
HRESULT CRilSimToolkitCommand::BuildSIMRECEIVEDATA(DWORD dwNotifyCode, BYTE bFifthByte, LPBYTE *ppbResult, DWORD *lpdwSize)
{
    HRESULT hr = S_OK;
    SIMRECEIVEDATA *psrd = NULL;
    DWORD dwSize;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMRECEIVEDATA\r\n")));

    bFifthByte;    // Avoid warning C4100: unreferenced formal parameter
    dwNotifyCode;  // Avoid warning C4100: unreferenced formal parameter

    // OK, let's put everything together here
    dwSize = ROUNDTODWORD(sizeof(SIMRECEIVEDATA)) + ROUNDTODWORD(m_dwAlphaIdLen) + ROUNDTODWORD(m_dwChannelDataLen);
    psrd = (SIMRECEIVEDATA *) new BYTE[dwSize];
    if (!psrd)
    {
        hr = E_OUTOFMEMORY;
        goto Exit;
    }

    memset(psrd, 0, dwSize);
    psrd->cbSize = dwSize;

    if (m_dwChannelDataLength != -1)
    {
        psrd->dwParams |= SIM_PARAM_SIMRECEIVEDATA_CHANNELDATALENGTH;
        psrd->dwChannelDataLength = m_dwChannelDataLength;
    }

    if (m_dwDeviceDestId)
    {
        psrd->dwParams |= SIM_PARAM_SIMRECEIVEDATA_CHANNELID;
        psrd->dwChannelId = m_dwDeviceDestId;
    }

    // Set up the text string, if it's there
    if (m_dwAlphaIdLen)
    {
        psrd->dwParams |= (SIM_PARAM_SIMRECEIVEDATA_TEXTSIZE | SIM_PARAM_SIMRECEIVEDATA_TEXTOFFSET);
        psrd->dwTextSize = m_dwAlphaIdLen;
        psrd->dwTextOffset = ROUNDTODWORD(sizeof(SIMRECEIVEDATA));
        lstrcpy(((TCHAR *) ((LPBYTE) psrd + psrd->dwTextOffset)), m_pwszAlphaId);
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconIdentifier)
    {
        psrd->dwParams |= SIM_PARAM_SIMRECEIVEDATA_ICONID;
        psrd->dwIconIdentifier = m_dwIconIdentifier;
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconQualifier)
    {
        psrd->dwParams |= SIM_PARAM_SIMRECEIVEDATA_ICONQUALIFIER;
        psrd->dwIconQualifier = m_dwIconQualifier;
    }

    *lpdwSize = dwSize;

Exit:
    *ppbResult = (LPBYTE) psrd;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMRECEIVEDATA\r\n")));
    return hr;
}

/****************************************************************************

    FUNCTION:   BuildSIMLANGUAGE

    PURPOSE:    Builds the SIMLANGUAGE structure

    PARAMETERS: dwNotifyCode - Which command is this?
                bFifthByte - The fifth byte from the command details
                ppbResult - OUT parameter to hold allocated structure

    RETURNS:    HRESULT

****************************************************************************/
HRESULT CRilSimToolkitCommand::BuildSIMLANGUAGE(DWORD dwNotifyCode, BYTE bFifthByte, LPBYTE *ppbResult, DWORD *lpdwSize)
{
    HRESULT hr = S_OK;
    SIMLANGUAGE *psl = NULL;
    DWORD dwSize;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMLANGUAGE\r\n")));

    bFifthByte;    // Avoid warning C4100: unreferenced formal parameter
    dwNotifyCode;  // Avoid warning C4100: unreferenced formal parameter

    // OK, let's put everything together here
    dwSize = ROUNDTODWORD(sizeof(SIMLANGUAGE));
    psl = (SIMLANGUAGE *) new BYTE[dwSize];
    if (!psl)
    {
        hr = E_OUTOFMEMORY;
        goto Exit;
    }

    memset(psl, 0, dwSize);
    psl->cbSize = dwSize;

    // Copy the language code if it's there. A blank language
    // code is sent to symbolize non-specific language.
    if (m_dwLanguageLen)
    {
        // The language code is defined in ISO 639 as a pair of
        // characters, copy up to the maximum language size and
        // null terminate.
        psl->dwParams |= SIM_PARAM_SIMLANGUAGE_LANGUAGE;
        _tcsncpy(psl->lpszLanguage, m_pwszLanguage, MAXLEN_LANGUAGE);
        psl->lpszLanguage[MAXLEN_LANGUAGE-1] = TEXT('\0');
    }

    *lpdwSize = dwSize;

Exit:
    *ppbResult = (LPBYTE) psl;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMLANGUAGE\r\n")));
    return hr;
}

/****************************************************************************

    FUNCTION:   BuildSIMRUNATCMD

    PURPOSE:    Builds the SIMRUNATCMD structure

    PARAMETERS: dwNotifyCode - Which command is this?
                bFifthByte - The fifth byte from the command details
                ppbResult - OUT parameter to hold allocated structure

    RETURNS:    HRESULT

****************************************************************************/
HRESULT CRilSimToolkitCommand::BuildSIMRUNATCMD(DWORD dwNotifyCode, BYTE bFifthByte, LPBYTE *ppbResult, DWORD *lpdwSize)
{
    HRESULT hr = S_OK;
    SIMRUNATCMD *psrac = NULL;
    DWORD dwSize;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMRUNATCMD\r\n")));

    bFifthByte;    // Avoid warning C4100: unreferenced formal parameter
    dwNotifyCode;  // Avoid warning C4100: unreferenced formal parameter

    // OK, let's put everything together here
    dwSize = ROUNDTODWORD(sizeof(SIMRUNATCMD)) + ROUNDTODWORD(m_dwAlphaIdLen) + ROUNDTODWORD(m_dwTextLen);
    psrac = (SIMRUNATCMD *) new BYTE[dwSize];
    if (!psrac)
    {
        hr = E_OUTOFMEMORY;
        goto Exit;
    }

    memset(psrac, 0, dwSize);
    psrac->cbSize = dwSize;

    // Set up the text string, if it's there
    if (m_dwAlphaIdLen)
    {
        psrac->dwParams |= (SIM_PARAM_SIMRUNATCMD_TEXTSIZE | SIM_PARAM_SIMRUNATCMD_TEXTOFFSET);
        psrac->dwTextSize = m_dwAlphaIdLen;
        psrac->dwTextOffset = ROUNDTODWORD(sizeof(SIMRUNATCMD));
        lstrcpy(((TCHAR *) ((LPBYTE) psrac + psrac->dwTextOffset)), m_pwszAlphaId);
    }

    // Set up the AT command string, if it's there
    if (m_dwTextLen)
    {
        psrac->dwParams |= (SIM_PARAM_SIMRUNATCMD_CMDSIZE | SIM_PARAM_SIMRUNATCMD_CMDOFFSET);
        psrac->dwCmdSize = m_dwTextLen;
        psrac->dwCmdOffset = ROUNDTODWORD(sizeof(SIMRUNATCMD)) + ROUNDTODWORD(m_dwAlphaIdLen);
        lstrcpy(((TCHAR *) ((LPBYTE) psrac + psrac->dwCmdOffset)), m_pwszText);
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconIdentifier)
    {
        psrac->dwParams |= SIM_PARAM_SIMRUNATCMD_ICONID;
        psrac->dwIconIdentifier = m_dwIconIdentifier;
    }

    if (SIMTKIT_INVALID_VALUE != m_dwIconQualifier)
    {
        psrac->dwParams |= SIM_PARAM_SIMRUNATCMD_ICONQUALIFIER;
        psrac->dwIconQualifier = m_dwIconQualifier;
    }

    *lpdwSize = dwSize;

Exit:
    *ppbResult = (LPBYTE) psrac;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::BuildSIMRUNATCMD\r\n")));
    return hr;
}

CRilSimToolkitResponse::CRilSimToolkitResponse()
{
    FUNCTION_TRACE(CRilSimToolkitResponse::CRilSimToolkitResponse);

#if defined(OEM2_SIMTOOLKIT)||defined(WAVECOM_DRIVER)     
    m_fTextFormat = TRUE;
#else
    m_fTextFormat = FALSE;
#endif //defined(OEM2_SIMTOOLKIT)
}

CRilSimToolkitResponse::~CRilSimToolkitResponse()
{
    FUNCTION_TRACE(CRilSimToolkitResponse::~CRilSimToolkitResponse);
}


HRESULT CRilSimToolkitResponse::CreateResponse(const RILSIMTOOLKITRSP* pRsp, LPBYTE pDetails, const DWORD dwDetailSize, LPSTR* pszDataRsp, DWORD *pdwDataRspSize )
{
    FUNCTION_TRACE(CRilSimToolkitResponse::CreateResponse);
    HRESULT hr = S_OK;

    // Assert parameters
    DEBUGCHK(NULL != pRsp);
    DEBUGCHK(NULL == *pszDataRsp);

    // Check parameters
    if (NULL == pRsp)
    {
        hr = E_INVALIDARG;
        goto Exit;
    }

    // Create radio specific response.
    if (TRUE == m_fTextFormat)
    {
        // Create buffer space to hold the Text response.

        *pdwDataRspSize = MAX_TEXT_RSP;
        *pszDataRsp = new CHAR[*pdwDataRspSize];
        if (NULL == *pszDataRsp)
        {
            DEBUGCHK(FALSE);
            hr = E_OUTOFMEMORY;
            goto Exit;
        }
        memset(*pszDataRsp, 0, *pdwDataRspSize);

        // Text style responses
#if defined(OEM2_SIMTOOLKIT)
        hr = TextFormatResponse(pRsp, pDetails, dwDetailSize, (LPBYTE)*pszDataRsp, pdwDataRspSize);
#else
        hr = TextFormatDFResponse(pRsp, pDetails, dwDetailSize, (LPBYTE)*pszDataRsp, pdwDataRspSize);   
#endif

        if (FAILED(hr) )
        {
            goto Exit;
        }
        else if ( 0 >= *pdwDataRspSize )
        {
            hr = E_FAIL;
            goto Exit;
        }
    }
    else
    {
        BYTE rgbTemp[MAX_BYTE_RSP];
        DWORD dwTempSize = ARRAY_LENGTH(rgbTemp);

        // Byte formatted SIMTKit commands
        hr = ByteFormatResponse(pRsp, pDetails, dwDetailSize, rgbTemp, &dwTempSize);

        // NOTE: we take ownership of allocated pszDataRsp
        if (!ComposeCmdWithByteArray("", rgbTemp, dwTempSize, "", *pszDataRsp))
        {
            DEBUGCHK(FALSE);
            *pdwDataRspSize = 0;
            *pszDataRsp = NULL;
            hr = E_OUTOFMEMORY;
            goto Exit;
        }

        // Set size returned for the text string with null termination.
        *pdwDataRspSize = strlen(*pszDataRsp) + 1;
    }

Exit:
    if(FAILED(hr))
    {
        if(*pszDataRsp)
        {
            delete[] *pszDataRsp;
            *pszDataRsp = NULL;
            *pdwDataRspSize = 0;
        }
    }
    return hr;
}

HRESULT CRilSimToolkitResponse::CreateEventDownload(const DWORD dwEvent, const LPBYTE pData, const DWORD dwDataSize, LPSTR* pszDataRsp, DWORD *pdwDataRspSize)
{
    FUNCTION_TRACE(CRilSimToolkitResponse::EventDownload);
    HRESULT hr = S_OK;

    // Assert parameters
    DEBUGCHK(NULL == *pszDataRsp);

    // Create radio specific response.
    if (TRUE == m_fTextFormat)
    {
        // Create buffer space to hold the Text response.

        *pdwDataRspSize = MAX_TEXT_RSP;
        *pszDataRsp = new CHAR[*pdwDataRspSize];
        if (NULL == *pszDataRsp)
        {
            DEBUGCHK(FALSE);
            hr = E_OUTOFMEMORY;
            goto Exit;
        }

        // Text style responses.
        // We take ownership of allocated pszDataRsp
        hr = TextEventDownload(dwEvent, pData, dwDataSize, *pszDataRsp, pdwDataRspSize);

        if (FAILED(hr) || (0 >= *pdwDataRspSize))
        {
            DEBUGCHK(FALSE);
            if (SUCCEEDED(hr))
            {
                hr = E_FAIL;
            }
            goto Exit;
        }
    }
    else
    {
        BYTE rgbTemp[MAX_BYTE_RSP];
        DWORD dwTempSize = ARRAY_LENGTH(rgbTemp);

        // Byte formatted SIMTKit commands
        hr = ByteEventDownload(dwEvent, pData, dwDataSize, rgbTemp, &dwTempSize);

        if (FAILED(hr) || (0 >= dwTempSize))
        {
            DEBUGCHK(FALSE);
            if (SUCCEEDED(hr))
            {
                hr = E_FAIL;
            }
            goto Exit;
        }

        // NOTE: we take ownership of allocated pszDataRsp
        if (!ComposeCmdWithByteArray("", rgbTemp, dwTempSize, "", *pszDataRsp))
        {
            DEBUGCHK(FALSE);
            hr = E_OUTOFMEMORY;
            goto Exit;
        }

        // Set size returned for the text string with null termination.
        *pdwDataRspSize = strlen(*pszDataRsp) + 1;
    }


Exit:
    if (FAILED(hr))
    {
        delete[] *pszDataRsp;
        *pszDataRsp = NULL;
        *pdwDataRspSize = 0;
    }

    return hr;
}


CRilSTKTerminalProfile::CRilSTKTerminalProfile()
{
    m_pbProfile = NULL;
    m_szProfileText = NULL;
    m_dwProfileSize = 0;
}

CRilSTKTerminalProfile::~CRilSTKTerminalProfile()
{
    if (m_pbProfile)
        delete[] m_pbProfile;
    if (m_szProfileText)
        delete[] m_szProfileText;
}

BOOL CRilSTKTerminalProfile::InitializeDefault(void)
{
    BYTE pbRegistryProfile[MAX_TERMINAL_PROFILE];
    DWORD dwRegistryProfileSize = MAX_TERMINAL_PROFILE;
    HKEY hRoot = HKEY_LOCAL_MACHINE;
    HKEY hKey;
    DWORD dwDisposition;
    BOOL bSuccess = FALSE;

    // Query the registry for a default terminal profile.
    if (ERROR_SUCCESS == RegCreateKeyEx(hRoot,
                                        g_tszRegKeyRIL,
                                        0, TEXT(""),
                                        0,
                                        0,
                                        0,
                                        &hKey,
                                        &dwDisposition))
    {
        bSuccess = (ERROR_SUCCESS == RegQueryValueEx(hKey,
                                                     gsc_szTerminalProfileRegKey,
                                                     0,
                                                     NULL,
                                                     pbRegistryProfile,
                                                     &dwRegistryProfileSize));
        RegCloseKey(hKey);
    }

    if (bSuccess && (0 < dwRegistryProfileSize))
    {
        // Successful retrieving registry settings, now set the internal data structures.
        bSuccess = SetTerminalProfile(pbRegistryProfile, dwRegistryProfileSize);
    }
    else
    {
        // If no registry default exists, use the hard coded default.
        bSuccess = SetDefaultTerminalProfile();
    }

    return bSuccess;
}

// Be careful with this function. If you change the object
// the pointer obtained may be invalidated.
LPCSTR CRilSTKTerminalProfile::GetText(void)
{
    return m_szProfileText;
}

BOOL CRilSTKTerminalProfile::SetByte(const LPBYTE pbValue, const DWORD dwSize)
{
    BOOL fSuccess = TRUE;

    // Check parameters
    ASSERT(NULL != pbValue);
    ASSERT(0 < dwSize);
    if (NULL == pbValue || 0 >= dwSize)
    {
        fSuccess = FALSE;
    }

    // Copy new terminal profile in.
    if (fSuccess)
    {
        fSuccess = SetTerminalProfile(pbValue, dwSize);
    }

    return fSuccess;
}

// Be careful with this function. If you change the object
// the pointer obtained may be invalidated.
const LPBYTE CRilSTKTerminalProfile::GetByte(void)
{
    // Try grabbing defaults if the profile does not exist.
    if (NULL == m_pbProfile)
    {
        ASSERT(FALSE);
        SetDefaultTerminalProfile();
    }

    return (const LPBYTE)m_pbProfile;
}

// Internal function for copy new set of bytes to terminal profile. Assumes
// input parameters have already been checked and are valid.
BOOL CRilSTKTerminalProfile::SetTerminalProfile(const LPBYTE pbValue, const DWORD dwSize)
{
    BOOL fSuccess = FALSE;

    // Clean up any existing profile information
    if (NULL != m_pbProfile)
        delete[] m_pbProfile;
    if (NULL != m_szProfileText)
        delete[] m_szProfileText;
    m_dwProfileSize = 0;

    // Copy bytes
    m_pbProfile = new BYTE[dwSize];
    if (NULL != m_pbProfile)
    {
        memcpy(m_pbProfile, pbValue, dwSize);
        m_dwProfileSize = dwSize;
    }

    // Create text version.
    // Enough space in the text buffer should be twice the size (2 text chars needed
    // to represent a byte) plus null termination.
    m_szProfileText = new CHAR[(dwSize * 2) + 1];
    if (NULL != m_szProfileText)
    {
        LPSTR szWalk = m_szProfileText;
        LPBYTE pbBytesWalk = pbValue;

        for (DWORD dwCur = 0; dwCur < dwSize; dwCur++)
        {
            *szWalk++ = SemiByteToChar(*pbBytesWalk,   TRUE);
            *szWalk++ = SemiByteToChar(*pbBytesWalk++, FALSE);
        }

        *szWalk = '\0';

        fSuccess = TRUE;
    }

    if (!fSuccess)
    {
        // Failed creating the terminal profile data. To maintain consistency, reset all
        // data to null.
        ASSERT(FALSE);

        if (m_pbProfile)
            delete[] m_pbProfile;
        if (m_szProfileText)
            delete[] m_szProfileText;

        m_pbProfile = NULL;
        m_szProfileText = NULL;
        m_dwProfileSize = 0;
    }

    return fSuccess;
}

DWORD CRilSTKTerminalProfile::GetSize(void)
{
    return m_dwProfileSize;
}

BOOL CRilSTKTerminalProfile::SetDefaultTerminalProfile(void)
{
    return SetTerminalProfile((const LPBYTE)gsc_pbDefTerminalProfile, DEF_TERMINAL_PROFILE_SIZE);
}

